世界就像一个巨大的图书馆,我们读着别人,做着自己,等待被读。 :

ES6的JavaScript数据结构实现之树(二叉搜索树、AVL树、红黑树)

目的:ES6标准下的JS数据结构的一些实现代码。(作为记录和启发)

内容:二叉搜索树。(未完成,待继续)

所有源码在我的Github上(如果觉得不错记得给星鼓励我哦):ES6的JavaScript数据结构实现之树(二叉搜索树、AVL树、红黑树)

一、基础数据结构

1、二叉搜索树(插入元素;树的遍历:中序,先序和后序;搜索树中的值;移除元素。)

  1 function defaultCompare(a, b) {
  2   if (a === b) {
  3     return Compare.EQUALS;
  4   }
  5   return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
  6 }
  7 const Compare = {
  8   LESS_THAN: -1,
  9   BIGGER_THAN: 1,
 10   EQUALS: 0
 11 };
 12 class Node {
 13   constructor(key) {
 14     this.key = key;
 15     this.left = undefined;
 16     this.right = undefined;
 17   }
 18 
 19   toString() {
 20     return `${this.key}`;
 21   }
 22 }
 23 
 24 class BinarySearchTree {
 25   constructor(compareFn = defaultCompare) {
 26     this.compareFn = compareFn;
 27     this.root = undefined;
 28   }
 29   insert(key) {
 30     if (this.root == null) {
 31       this.root = new Node(key);
 32     } else {
 33       this.insertNode(this.root, key);
 34     }
 35 
 36   }
 37   insertNode(node, key) {
 38     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
 39       if (node.left == null) {
 40         node.left = new Node(key);
 41       } else {
 42         this.insertNode(node.left, key);
 43       }
 44     } else if (node.right == null) {
 45       node.right = new Node(key);
 46     } else {
 47       this.insertNode(node.right, key);
 48     }
 49   }
 50   inOrderTraverse(callback) {
 51     this.inOrderTraverseNode(this.root, callback);
 52   }
 53   inOrderTraverseNode(node, callback) {
 54     if(node != null) {
 55       this.inOrderTraverseNode(node.left, callback);
 56       callback(node.key);
 57       this.inOrderTraverseNode(node.right, callback);
 58     }
 59   }
 60    preOrderTraverse(callback) {
 61     this.preOrderTraverseNode(this.root, callback);
 62   }
 63 
 64   preOrderTraverseNode(node, callback) {
 65     if (node != null) {
 66       callback(node.key);
 67       this.preOrderTraverseNode(node.left, callback);
 68       this.preOrderTraverseNode(node.right, callback);
 69     }
 70   }
 71   postOrderTraverse(callback) {
 72     this.postOrderTraverseNode(this.root, callback);
 73   }
 74 
 75   postOrderTraverseNode(node, callback) {
 76     if (node != null) {
 77       this.postOrderTraverseNode(node.left, callback);
 78       this.postOrderTraverseNode(node.right, callback);
 79       callback(node.key);
 80     }
 81   }
 82   min() {
 83     return this.minNode(this.root);
 84   }
 85   minNode(node) {
 86     let current = node;
 87     while (current != null && current.left != null) {
 88       current = current.left;
 89     }
 90     return current;
 91   }
 92   max() {
 93     return this.maxNode(this.root);
 94   }
 95 
 96   maxNode(node) {
 97     let current = node;
 98     while (current != null && current.right != null) {
 99       current = current.right;
100     }
101     return current;
102   }
103   search(key) {
104     return this.searchNode(this.root, key);
105   }
106   searchNode(node, key) {
107     if (node == null) {
108       return false;
109     }
110     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
111       return this.searchNode(node.left, key);
112     }
113     if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
114       return this.searchNode(node.right, key);
115     }
116     return true;
117   }
118   remove(key) {
119     this.root = this.removeNode(this.root, key);
120 
121   }
122  removeNode(node, key) {
123     if (node == null) {
124       return undefined;
125     }
126     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
127       node.left = this.removeNode(node.left, key);
128       return node;
129     } if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
130       node.right = this.removeNode(node.right, key);
131       return node;
132     }
133     // key is equal to node.item
134     // handle 3 special conditions
135     // 1 - a leaf node
136     // 2 - a node with only 1 child
137     // 3 - a node with 2 children
138     // case 1
139     if (node.left == null && node.right == null) {
140       node = undefined;
141       return node;
142     }
143     // case 2
144     if (node.left == null) {
145       node = node.right;
146       return node;
147     } if (node.right == null) {
148       node = node.left;
149       return node;
150     }
151     // case 3
152     const aux = this.minNode(node.right);
153     node.key = aux.key;
154     node.right = this.removeNode(node.right, aux.key);
155     return node;
156   }
157   
158 }
159 
160 const tree = new BinarySearchTree();
161 tree.insert(11);
162 tree.insert(12);
163 tree.insert(7);
164 tree.insert(5);
165 tree.insert(13);
166 console.log(tree);
167 tree.insert(8);
168 tree.insert(3);
169 console.log(tree);
170 
171 const printNode = (value) => console.log(value);
172 tree.inOrderTraverse(printNode);
173 console.log('******');
174 tree.preOrderTraverse(printNode);
175 console.log('******');
176 tree.postOrderTraverse(printNode);
177 console.log('******');
178 console.log(tree.min());
179 console.log(tree.max());
180 console.log(tree.search(7));
181 console.log(tree.search(6));
182 console.log(tree);
183 tree.remove(12);
184 console.log(tree);
BinarySearchTree

 

二、二叉搜索树的扩展(自平衡树、AVL树、红黑树)

BST存在一个问题:取决于我们添加的节点数,数的一条边可能会非常深。这会在需要在某条边上添加、移除和搜索某个节点时引起的一些性能问题。为解决这个问题,有一种树叫Adelson-Velskii-Landi树(AVL树)。AVL树是一种自平衡的二叉搜索树(任何一个节点左右两侧子树的高度之差最多为1)。此外,红黑树也是一个自平衡二叉搜索树(如果需要一个包含多次插入和删除的自平衡树,红黑树要优于AVL树)。

 1、Adelson-Velskii-Landi树(AVL树)(节点的高度和平衡因子;平衡操作--AVL旋转;插入节点;移除节点)

  1 function defaultCompare(a, b) {
  2   if (a === b) {
  3     return Compare.EQUALS;
  4   }
  5   return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
  6 }
  7 const Compare = {
  8   LESS_THAN: -1,
  9   BIGGER_THAN: 1,
 10   EQUALS: 0
 11 };
 12 class Node {
 13   constructor(key) {
 14     this.key = key;
 15     this.left = undefined;
 16     this.right = undefined;
 17   }
 18 
 19   toString() {
 20     return `${this.key}`;
 21   }
 22 }
 23 
 24 class BinarySearchTree {
 25   constructor(compareFn = defaultCompare) {
 26     this.compareFn = compareFn;
 27     this.root = undefined;
 28   }
 29   insert(key) {
 30     if (this.root == null) {
 31       this.root = new Node(key);
 32     } else {
 33       this.insertNode(this.root, key);
 34     }
 35 
 36   }
 37   insertNode(node, key) {
 38     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
 39       if (node.left == null) {
 40         node.left = new Node(key);
 41       } else {
 42         this.insertNode(node.left, key);
 43       }
 44     } else if (node.right == null) {
 45       node.right = new Node(key);
 46     } else {
 47       this.insertNode(node.right, key);
 48     }
 49   }
 50   inOrderTraverse(callback) {
 51     this.inOrderTraverseNode(this.root, callback);
 52   }
 53   inOrderTraverseNode(node, callback) {
 54     if(node != null) {
 55       this.inOrderTraverseNode(node.left, callback);
 56       callback(node.key);
 57       this.inOrderTraverseNode(node.right, callback);
 58     }
 59   }
 60    preOrderTraverse(callback) {
 61     this.preOrderTraverseNode(this.root, callback);
 62   }
 63 
 64   preOrderTraverseNode(node, callback) {
 65     if (node != null) {
 66       callback(node.key);
 67       this.preOrderTraverseNode(node.left, callback);
 68       this.preOrderTraverseNode(node.right, callback);
 69     }
 70   }
 71   postOrderTraverse(callback) {
 72     this.postOrderTraverseNode(this.root, callback);
 73   }
 74 
 75   postOrderTraverseNode(node, callback) {
 76     if (node != null) {
 77       this.postOrderTraverseNode(node.left, callback);
 78       this.postOrderTraverseNode(node.right, callback);
 79       callback(node.key);
 80     }
 81   }
 82   min() {
 83     return this.minNode(this.root);
 84   }
 85   minNode(node) {
 86     let current = node;
 87     while (current != null && current.left != null) {
 88       current = current.left;
 89     }
 90     return current;
 91   }
 92   max() {
 93     return this.maxNode(this.root);
 94   }
 95 
 96   maxNode(node) {
 97     let current = node;
 98     while (current != null && current.right != null) {
 99       current = current.right;
100     }
101     return current;
102   }
103   search(key) {
104     return this.searchNode(this.root, key);
105   }
106   searchNode(node, key) {
107     if (node == null) {
108       return false;
109     }
110     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
111       return this.searchNode(node.left, key);
112     }
113     if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
114       return this.searchNode(node.right, key);
115     }
116     return true;
117   }
118   remove(key) {
119     this.root = this.removeNode(this.root, key);
120 
121   }
122  removeNode(node, key) {
123     if (node == null) {
124       return undefined;
125     }
126     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
127       node.left = this.removeNode(node.left, key);
128       return node;
129     } if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
130       node.right = this.removeNode(node.right, key);
131       return node;
132     }
133     // key is equal to node.item
134     // handle 3 special conditions
135     // 1 - a leaf node
136     // 2 - a node with only 1 child
137     // 3 - a node with 2 children
138     // case 1
139     if (node.left == null && node.right == null) {
140       node = undefined;
141       return node;
142     }
143     // case 2
144     if (node.left == null) {
145       node = node.right;
146       return node;
147     } if (node.right == null) {
148       node = node.left;
149       return node;
150     }
151     // case 3
152     const aux = this.minNode(node.right);
153     node.key = aux.key;
154     node.right = this.removeNode(node.right, aux.key);
155     return node;
156   }
157   
158 }
159 const BalanceFactor = {
160   UNBALANCED_RIGHT: 1,
161   SLIGHTLY_UNBALANCED_RIGHT: 2,
162   BALANCED: 3,
163   SLIGHTLY_UNBALANCED_LEFT: 4,
164   UNBALANCED_LEFT: 5
165 };
166 class AVLTree extends BinarySearchTree {
167   constructor(compareFn = defaultCompare) {
168     super(compareFn);
169     this.compareFn = compareFn;
170     this.root = null;
171   }
172   getNodeHeigh(node) {
173     if (node == null) {
174       return -1;
175     }
176     return Max.max (
177       this.getNodeHeigh(node.left), this.getNodeHeigh(node.right)
178       ) + 1;
179   }
180   getBalanceFactor(node) {
181     const heightDifference = this.getNodeHeigh(node.left) - 
182     this.getNodeHeigh(node.right);
183     switch (heightDifference) {
184       case -2:
185         return BalanceFactor.UNBALANCED_RIGHT;
186       case -1:
187         return BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT;
188       case 1:
189         return BalanceFactor.SLIGHTLY_UNBALANCED_LEFT;
190       case 2:
191         return BalanceFactor.UNBALANCED_LEFT;
192       default:   
193         return BalanceFactor.BALANCED;
194     }
195   }
196   rotationLL(node) {
197     const tmp = node.left;
198     node.left = tmp.right;
199     tmp.right = node;
200     return tmp;
201   }
202   rotationRR(node) {
203     const tmp = node.right;
204     node.right = tmp.left;
205     tmp.left = node;
206     return tmp;
207   }
208   rotationLR(node) {
209     node.left = this.rotationRR(node.left);
210     return this.rotationLL(node);
211   }
212   rotationRL(node) {
213     node.right = this.ratationLL(node.right);
214     return this.rotationRR(node);
215   }
216   insert(key) {
217     this.root = this.insertNode(this.root, key);
218   }
219   insertNode(node, key) {
220     if(node == null) {
221       return new Node(key);
222     }
223     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
224       node.left = this.insertNode(node.left, key);
225     } else if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
226       node.right = this.insertNode(node.right, key);
227     } else {
228       return node;
229     }
230     const balanceFactor = this.getBalanceFactor(node);
231     if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {
232       if (this.compareFn(key, node.left.key) === Compare.LESS_THAN) {
233         node = this.rotationLL(node);
234       } else {
235         return this.rotationLR(node); 
236       }
237     }
238     if (balanceFactor === BalanceFactor.UNBALANCED_RIGHT) {
239       if (this.compareFn(key, node.right.key) === Compare.BIGGER_THAN) {
240         node = this. rotationRR(node);
241       } else {
242         return this.rotationRL(node);
243       }
244     }
245     return node;
246   }
247 
248   removeNode(node, key) {
249     node = super.removeNode(node, key);
250     if (node == null) {
251       return node;
252     }
253     const balanceFactor = this.getBalanceFactor(node);
254     if (balanceFactor === BalanceFactor.UNBALANCED_LEFT) {
255       if (
256         balanceFactorLeft === BalanceFactor.BALANCED || 
257         balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT
258         ) {
259         return this.rotationLL(node);
260       }
261       if (
262         balanceFactorLeft === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT
263         ) {
264         return this.rotationLR(node.left);
265       }
266     }
267     if (BalanceFactor === BalanceFactor.UNBALANCED_RIGHT) {
268       if (
269         balanceFactorRight === BalanceFactor.BALANCED || 
270         balanceFactorRight === BalanceFactor.SLIGHTLY_UNBALANCED_RIGHT
271         ) {
272         return this.rotationRR(node);
273 
274       }
275       if (
276         balanceFactorRight === BalanceFactor.SLIGHTLY_UNBALANCED_LEFT
277         ) {
278         return this.rotationRL(node.right);
279       }
280     }
281     return node;
282   }
283 
284 
285 
286 }
AVlTree

 

2、红黑树(红黑树的规则;重新填色和旋转;插入节点;移除节点;)

  1 function defaultCompare(a, b) {
  2   if (a === b) {
  3     return Compare.EQUALS;
  4   }
  5   return a < b ? Compare.LESS_THAN : Compare.BIGGER_THAN;
  6 }
  7 const Compare = {
  8   LESS_THAN: -1,
  9   BIGGER_THAN: 1,
 10   EQUALS: 0
 11 };
 12 class Node {
 13   constructor(key) {
 14     this.key = key;
 15     this.left = undefined;
 16     this.right = undefined;
 17   }
 18 
 19   toString() {
 20     return `${this.key}`;
 21   }
 22 }
 23 
 24 class BinarySearchTree {
 25   constructor(compareFn = defaultCompare) {
 26     this.compareFn = compareFn;
 27     this.root = undefined;
 28   }
 29   insert(key) {
 30     if (this.root == null) {
 31       this.root = new Node(key);
 32     } else {
 33       this.insertNode(this.root, key);
 34     }
 35 
 36   }
 37   insertNode(node, key) {
 38     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
 39       if (node.left == null) {
 40         node.left = new Node(key);
 41       } else {
 42         this.insertNode(node.left, key);
 43       }
 44     } else if (node.right == null) {
 45       node.right = new Node(key);
 46     } else {
 47       this.insertNode(node.right, key);
 48     }
 49   }
 50   inOrderTraverse(callback) {
 51     this.inOrderTraverseNode(this.root, callback);
 52   }
 53   inOrderTraverseNode(node, callback) {
 54     if(node != null) {
 55       this.inOrderTraverseNode(node.left, callback);
 56       callback(node.key);
 57       this.inOrderTraverseNode(node.right, callback);
 58     }
 59   }
 60    preOrderTraverse(callback) {
 61     this.preOrderTraverseNode(this.root, callback);
 62   }
 63 
 64   preOrderTraverseNode(node, callback) {
 65     if (node != null) {
 66       callback(node.key);
 67       this.preOrderTraverseNode(node.left, callback);
 68       this.preOrderTraverseNode(node.right, callback);
 69     }
 70   }
 71   postOrderTraverse(callback) {
 72     this.postOrderTraverseNode(this.root, callback);
 73   }
 74 
 75   postOrderTraverseNode(node, callback) {
 76     if (node != null) {
 77       this.postOrderTraverseNode(node.left, callback);
 78       this.postOrderTraverseNode(node.right, callback);
 79       callback(node.key);
 80     }
 81   }
 82   min() {
 83     return this.minNode(this.root);
 84   }
 85   minNode(node) {
 86     let current = node;
 87     while (current != null && current.left != null) {
 88       current = current.left;
 89     }
 90     return current;
 91   }
 92   max() {
 93     return this.maxNode(this.root);
 94   }
 95 
 96   maxNode(node) {
 97     let current = node;
 98     while (current != null && current.right != null) {
 99       current = current.right;
100     }
101     return current;
102   }
103   search(key) {
104     return this.searchNode(this.root, key);
105   }
106   searchNode(node, key) {
107     if (node == null) {
108       return false;
109     }
110     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
111       return this.searchNode(node.left, key);
112     }
113     if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
114       return this.searchNode(node.right, key);
115     }
116     return true;
117   }
118   remove(key) {
119     this.root = this.removeNode(this.root, key);
120 
121   }
122  removeNode(node, key) {
123     if (node == null) {
124       return undefined;
125     }
126     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
127       node.left = this.removeNode(node.left, key);
128       return node;
129     } if (this.compareFn(key, node.key) === Compare.BIGGER_THAN) {
130       node.right = this.removeNode(node.right, key);
131       return node;
132     }
133     // key is equal to node.item
134     // handle 3 special conditions
135     // 1 - a leaf node
136     // 2 - a node with only 1 child
137     // 3 - a node with 2 children
138     // case 1
139     if (node.left == null && node.right == null) {
140       node = undefined;
141       return node;
142     }
143     // case 2
144     if (node.left == null) {
145       node = node.right;
146       return node;
147     } if (node.right == null) {
148       node = node.left;
149       return node;
150     }
151     // case 3
152     const aux = this.minNode(node.right);
153     node.key = aux.key;
154     node.right = this.removeNode(node.right, aux.key);
155     return node;
156   }
157   
158 }
159 
160 class RedBlackNode extends Node {
161   constructor(key) {
162     super(key);
163     this.key = key;
164     this.color = Colors.RED;
165     this.parent = null;
166   }
167   isRed() {
168     return this.color === Colors.RED;
169   }
170 }
171 
172 class RedBlackTree extends BinarySearchTree {
173   constructor(compareFn = defaultCompare) {
174     super(compareFn);
175     this.compareFn = compareFn;
176     this.root = null;
177   }
178   insert(key) {
179     if (this.root == null) {
180       this.root = new RedBlackNode(key);
181       this.root.color = Colors.BLACK;
182     } else {
183       const newNode = this.inserNode(this.root, key);
184       this.fixTreeProperties(newNode);
185     }
186   }
187   insertNode(node, key) {
188     if (this.compareFn(key, node.key) === Compare.LESS_THAN) {
189       if (node.left == null) {
190         node.left = new RedBlackNode(key);
191         node.left.parent = node;
192         return node.left;
193       }
194       else {
195         return this.insertNode(node.left, key);
196       }
197     }
198     else if (node.right == null) {
199       node.right = new RedBlackNode(key);
200       node.right.parent = node;
201       return node.right;
202     }
203     else {
204       return this.insertNode(node.right, key);
205     } 
206   }
207   fixTreeProperties(node) {
208     while (node && node.parent && node.parent.color.isRed() 
209       && node.color !== Colors.BLACK) {
210       let parent = node.parent;
211       const grandParent = parent.parent;
212       if (grandParent && grandParent.left === parent) {
213         const uncle = grandParent.right;
214         if (uncle && uncle.color === Colors.RED) {
215           grandParent.color = Colors.RED;
216           parent.color = Colors.BLACK;
217           uncle.color = Colors.BLACK;
218           node = grandParent;
219         }
220         else {
221           if (node === parent.right) {
222             this.rotationRR(parent);
223             node = parent;
224             parent = node.parent;  
225           }
226           this.rotationLL(grandParent);
227           parent.color = Colors.BLACK;
228           grandParent.color = Colors.RED;
229           node = parent;
230 
231         }
232       }
233       else {
234         const uncle = grandParent.left;
235         if (uncle && uncle.color === Colors.RED) {
236           grandParent.color = Colors.RED;
237           parent.color = Colors.BLACK;
238           uncle.color = Colors.BLACK;
239           node = grandParent;
240         }
241         else {
242           if (node === parent.left) {
243             this.rotationLL(parent);
244             node = parent;
245             parent = node.parent;
246           }
247           this.rotationRR(grandParent);
248           parent.color = Colors.BLACK;
249           grandParent.color = Colors.RED;
250           node = parent;
251         }
252       }
253 
254 
255     }
256     this.root.color = Colors.BLACK;
257   }
258   rotationLL(node) {
259     const tmp = node.left;
260     node.left = tmp.right;
261     if (tmp.right && tmp.right.key) {
262       tmp.right.parent = node;
263     }
264     tmp.parent = node.parent;
265     if (!node.parent) {
266       this.root = tmp;
267     }
268     else {
269       if(node === node.parent.left) {
270         node.parent.left = tmp;
271       } 
272       else {
273         node.parent.right = tmp;
274       }
275     }
276     tmp.right = node;
277     node.parent = tmp;
278   }
279   rotationRR(node) {
280     const tmp = node.right;
281     node.right = tmp.left;
282     if (tmp.left && tmp.left.key) {
283       tmp.left.parent = node;
284     }
285     tmp.parent = node.parent;
286     if (!node.parent) {
287       this.root = tmp;
288     }
289     else {
290       if (node === node.parent.left) {
291         node.parent.left = tmp;
292       }
293       else {
294         node.parent.right = tmp;
295       }
296     }
297     tmp.left = node;
298     node.parent = tmp;
299   }
300 
301 }
RedBlackTree

 

posted @ 2019-10-21 16:22  Secret_Wu  阅读(886)  评论(0编辑  收藏  举报