赞
踩
红黑树是数据结构中比较困难的部分,这里只简单写一下规则,具体封装代码比较复杂,不敲了。详细笔记请看大佬博客:图解红黑树
变色、左旋转、右旋转
为了重新符合红黑树的规则,需要把红色节点变为黑色,或者把黑色节点变为红色;
插入的新节点通常都是红色节点:
当插入的节点为红色的时候,大多数情况不违反红黑树的任何规则;
而插入黑色节点,必然会导致一条路径上多了一个黑色节点,这是很难调整的;
红色节点虽然可能导致红红相连的情况,但是这种情况可以通过颜色调换和旋转来调整;
以节点X为根逆时针旋转二叉搜索树,使得父节点原来的位置被自己的右子节点替代,左子节点的位置被父节点替代;
以节点X为根顺时针旋转二叉搜索树,使得父节点原来的位置被自己的左子节点替代,右子节点的位置被父节点替代;
当插入的新节点N位于树的根上时,没有父节点。
这种情况下,只需要将红色节点变为黑色节点即可满足规则2 。
新界点N的父节点P为黑色节点,此时不需要任何变化。
节点P为红色,节点U也为红色,此时节点G必为黑色,即父红叔红祖黑。
这种情况下需要把父红叔红祖黑
=> 父黑叔黑祖红
节点P是红色节点,节点U是黑色节点,并且节点N为节点P的左子节点,此时节点G一定是黑色节点,即父红叔黑祖黑。
节点P是红色节点,节点U是黑色节点,并且节点N为节点P的右子节点,此时节点G一定是黑色节点,即父红叔黑祖黑。
在这种情况下需要:
图结构是一种与树结构有些相似的数据结构,主要特点是:
其他有关图的表述详见大佬博客:js实现图结构
图结构应该有两个属性,顶点和边
其中字典我们用之前封装的那个结构(当然其实用ES6自带的Map也可以)
//封装一个图结构,其中要设置两个属性
//vertexes存储顶点有哪些
//edges存储的是顶点和边集合的键值对
class Graph {
constructor() {
this.vertexes = []; //存储顶点
this.edges = new Map(); //存储顶点和边的对应关系
}
}
1、添加顶点:两个属性都要添加,在edges中应该初始化一个空数组用来存储边的对应
2、添加边:传两个参数,分别是连个顶点,由于我们搞的是无向边,所以要互相指一下
//封装一个图结构,其中要设置两个属性 //vertexes存储顶点有哪些 //edges存储的是顶点和边集合的键值对 class Graph { constructor() { this.vertexes = []; //存储顶点 this.edges = new Map(); //存储顶点和边的对应关系 } //添加顶点 addVertex(v) { this.vertexes.push(v); //添加顶点的同时要初始化存储顶点对应边的数据结构 this.edges.set(v, []); //这里使用数组存储边 } //添加边(无向边,需要互相指一下) addEdge(v1, v2) { this.edges.get(v1).push(v2); this.edges.get(v2).push(v1); } }
以邻接表的形式输出,即输出每个顶点及该顶点对应的边关系们
代码:
//转字符串
toString() {
let result = '';
for(let i = 0; i < this.vertexes.length; i++) {
let vertex = this.vertexes[i];
result += vertex + ' => ';
let vLinks = this.edges.get(vertex);//拿到连接的顶点们
for(let i = 0; i < vLinks.length; i++) {
let edge = vLinks[i];
result += edge + ' ';
}
result += '\n';
}
return result;
}
上面这段代码并不难,如果看不懂就多捋一捋
测试代码:
//测试代码 let graph = new Graph(); let myVertexes = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']; //这里最好循环添加,因为我们除了添加顶点之外,还要初始化顶点对应的边数组 for(let i = 0; i < myVertexes.length; i++) { graph.addVertex(myVertexes[i]); } //3.添加边 graph.addEdge('A', 'B') graph.addEdge('A', 'C') graph.addEdge('A', 'D') graph.addEdge('C', 'D') graph.addEdge('C', 'G') graph.addEdge('D', 'G') graph.addEdge('D', 'H') graph.addEdge('B', 'E') graph.addEdge('B', 'F') graph.addEdge('E', 'I') //4.输出结果 console.log(graph.toString());
我们添加的这个图应该是这样一个结构:
控制台输出结果:
非常的优雅。
图的遍历思想与树的遍历思想一样,意味着需要将图中所有的顶点都访问一遍,并且不能有重复的访问(上面的toString方法会重复访问,比如访问A的时候访问B,然后又访问B,B里边又访问A……);
遍历有两种:广度优先遍历、深度优先遍历
两种遍历算法都需要指定第一个被访问的顶点
;
在开始之前,先介绍个我没见过的操作:
往数组里存键值对,键是字符串的形式,这我还真没见过艹
let colors = [];
colors['A'] = 'white';
colors['B'] = 'white';
console.log(colors); //[A: 'white', B: 'white']
1、用颜色作为是否已访问节点的标识
white
:未入队(未访问), grey
:在队列中(访问中), black
:已出队(完全访问)
初始化时颜色全部改成白色
initializeColor() {
let colors = [];
for(let i = 0; i < this.vertex.length; i++) {
//全部初始化为白色(未访问)
colors[this.vertex[i]] = 'white';
}
return colors;
}
2、利用队列实现
主要思路图解:
主要思路:
1、顶点先入队
2、开启循环,只要队列不为空,就继续循环
3、循环中,首先从队头取出顶点,该顶点出队说明访问完成,颜色改为黑色,输出顶点
4、本轮循环中,继续将已输出顶点的连接顶点们依次入队
5、它们入队时一定要注意,要判断是否已经在队列中或者已经出队,判断的条件很简单,只要颜色是white说明就还没入队,入队后颜色改为gery。(如果不写这个判断,那么由于顶点会有重复遍历的情况,顶点之间的相互连接导致已经在队列的顶点
和已经出队的顶点
会重复入队,这样的话就死循环了)
6、遍历结束(这里默认输出顶点就叫遍历了)
//广度优先遍历(利用队列实现),需要传入开始的顶点 bfs(initV) { //1.初始化颜色 let colors = this.initializeColor(); //2.声明一个队列,开始顶点先入队 let queue = new Queue(); queue.enqueue(initV); //3.开始遍历,只要队列不为空就继续遍历 while(!queue.isEmpty()) { //3.1从队头取出一个顶点 let front = queue.dequeue(); console.log(front); colors[front] = 'black'; //3.2出队的顶点的连接顶点依次入队,同时更改颜色 let vLinks = this.edges.get(front); for(let i = 0; i < vLinks.length; i++) { //这里一定要判断是否已经入队,不然会陷入死循环 if(colors[vLinks[i]] == 'white') { queue.enqueue(vLinks[i]); colors[vLinks[i]] = 'grey'; } } } }
利用栈实现,或者利用递归实现(递归的本质也是函数调用栈)
主要思路:
1、所有顶点初始化为白色
2、调用递归函数(递归函数一定要单独写,不然每次都初始化白色,就栈溢出了)
3、递归函数中先输出,输出完后改为黑色
4、拿到邻居顶点,遍历,如果是白色(未入栈)就递归调用入栈
5、依次访问,然后回去,再访问,直到全部出栈
代码:
//深度优先遍历(利用递归实现) dfs(initV) { //1.把所有的顶点初始化为白色 let colors = this.initializeColor(); //2.遍历顶点 this.dfsRecursion(initV, colors); } //递归函数 dfsRecursion(initV, colors) { console.log(initV); //访问并输出 colors[initV] = 'black'; //遍历完改为黑色 let vLinks = this.edges.get(initV); //拿到邻居 for (let i = 0; i < vLinks.length; i++) { if (colors[vLinks[i]] == 'white') { this.dfsRecursion(vLinks[i],colors); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。