zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    搞破坏(手动滑稽),如何写出让同事无法维护的代码?
    我们公司是如何把项目中的2100个if-else彻底干掉的
    为什么阿里规定需在事务注解@Transactional中指定rollbackFor?
    算法导论 10.2-7
    算法导论 10.2-3
    算法导论 10.2-2
    算法导论 10.1-7
    算法导论 10.1-6
    算法导论 2.3-7
    算法导论 2.3-5 二分查找
  • 原文地址:https://www.cnblogs.com/xinkuiwu/p/11714250.html
Copyright © 2011-2022 走看看