Advertisement
ouija_bh

Red-black tree using open content

Sep 10th, 2023 (edited)
140
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 24.51 KB | Source Code | 0 0
  1. /* An implementation of left-leaning red-black tree. It has tree methods
  2.  * add, remove, findLE, findEQ, findGE, @@iterator, size, and clear.
  3.  * Ported from Open Data Structures by Pat Morin. Includes a short
  4.  * demonstration of those methods showing traversals of modified tree.
  5.  */
  6.  
  7. // Vertex colors. credit: Morin 9.2.
  8. const red = 0, black = 1;
  9.  
  10. /** A node. */
  11. class Vertex {
  12.   /** constructor() credit: Morin 6.1, 9.2. */
  13.   constructor() {
  14.     this.value;  // any
  15.     this.left;   // Vertex ref
  16.     this.right;  // Vertex ref
  17.     this.parent; // Vertex ref
  18.     this.color;  // number
  19.     this.bSeen;  // boolean
  20.   }
  21. }
  22.  
  23. /** A sorted set. */
  24. class RedBlackTree {
  25.   #nil; #root; #numV; #compare;
  26.   /** constructor() credit: Morin BinaryTree.java, BinarySearchTree.java, RedBlackTree.java.
  27.    * @param {function} comparator function taking (any, any) and returning -1, 0, or 1
  28.    */
  29.   constructor(comparator) {
  30.     this.#nil = new Vertex();  // vertex used as null
  31.     this.#root = this.#nil;  // root vertex
  32.     this.#numV = 0;   // number of vertices
  33.     this.#compare = comparator;
  34.  
  35.     this.#nil.color = black;
  36.   }
  37.  
  38.   /** #newVertex() credit: Morin BinaryTree.java, BinarySearchTree.java.
  39.    * @param {any} value value used to order the tree
  40.    * @returns {Vertex} a new vertex
  41.    */
  42.   #newVertex(value) {
  43.     var vertex = new Vertex();
  44.     vertex.value = value;
  45.     vertex.left = this.#nil;
  46.     vertex.right = this.#nil;
  47.     vertex.parent = this.#nil;
  48.     vertex.bSeen = false;
  49.     return vertex;
  50.   }
  51.  
  52.   /** #firstVertex() credit: Morin BinaryTree.java.
  53.    * @returns {Vertex} first vertex reported in in-order traversal
  54.    */
  55.   #firstVertex() {
  56.     var vertex = this.#root;
  57.     if (vertex == this.#nil) { return this.#nil; }
  58.     while (vertex.left != this.#nil) {
  59.       vertex = vertex.left;
  60.     }
  61.     return vertex;
  62.   }
  63.  
  64.   /** #nextVertex() credit: Morin BinaryTree.java.
  65.    * @param {Vertex} vertex a vertex
  66.    * @returns {Vertex} vertex following the given in in-order traversal
  67.    */
  68.   #nextVertex(vertex) {
  69.     if (vertex.right != this.#nil) {
  70.       vertex = vertex.right;
  71.       while (vertex.left != this.#nil) {
  72.         vertex = vertex.left;
  73.       }
  74.     } else {
  75.       while (vertex.parent != this.#nil && vertex.parent.left != vertex) {
  76.         vertex = vertex.parent;
  77.       }
  78.       vertex = vertex.parent;
  79.     }
  80.     return vertex;
  81.   }
  82.  
  83.   /** @@iterator() Iterator of in-order values. credit: Morin BinarySearchTree.java. */
  84.   *[Symbol.iterator]() {
  85.     var cur = this.#firstVertex();
  86.     while(cur != this.#nil) {
  87.       var value = cur.value;
  88.       cur = this.#nextVertex(cur);
  89.       yield value;
  90.     }
  91.   }
  92.  
  93.   /** toString() credit: Morin BinarySearchTree.java.
  94.    * @returns {string} in-order values formatted as array
  95.    */
  96.   toString() {
  97.     return JSON.stringify([...this]);
  98.   }
  99.  
  100.   /** #pushBlack() credit: Morin 9.2.2.
  101.    * @param {Vertex} vertex vertex to push black
  102.    */
  103.   #pushBlack(vertex) {
  104.     vertex.color--;
  105.     vertex.left.color++;
  106.     vertex.right.color++;
  107.   }
  108.  
  109.   /** #pullBlack() credit: Morin 9.2.2.
  110.    * @param {Vertex} vertex vertex to pull black
  111.    */
  112.   #pullBlack(vertex) {
  113.     vertex.color++;
  114.     vertex.left.color--;
  115.     vertex.right.color--;
  116.   }
  117.  
  118.   /** #swapColors() credit: Morin RedBlackTree.java.
  119.    * @param {Vertex} a a vertex
  120.    * @param {Vertex} b another vertex
  121.    */
  122.   #swapColors(a, b) {
  123.     var c = a.color;
  124.     a.color = b.color;
  125.     b.color = c;
  126.   }
  127.  
  128.   /** #rotateLeft() credit: Morin 7.2.
  129.    * @param {Vertex} vertex vertex to rotate left
  130.    */
  131.   #rotateLeft(vertex) {
  132.     var cur = vertex.right;
  133.     cur.parent = vertex.parent;
  134.     if (cur.parent != this.#nil) {
  135.       if (cur.parent.left == vertex) { cur.parent.left = cur; }
  136.       else { cur.parent.right = cur; }
  137.     }
  138.     vertex.right = cur.left;
  139.     if (vertex.right != this.#nil) {
  140.       vertex.right.parent = vertex;
  141.     }
  142.     vertex.parent = cur;
  143.     cur.left = vertex;
  144.     if (vertex == this.#root) {
  145.       this.#root = cur;
  146.       this.#root.parent = this.#nil;
  147.     }
  148.   }
  149.  
  150.   /** #rotateRight() credit: Morin 7.2.
  151.    * @param {Vertex} vertex vertex to rotate right
  152.    */
  153.   #rotateRight(vertex) {
  154.     var cur = vertex.left;
  155.     cur.parent = vertex.parent;
  156.     if (cur.parent != this.#nil) {
  157.       if (cur.parent.left == vertex) { cur.parent.left = cur; }
  158.       else { cur.parent.right = cur; }
  159.     }
  160.     vertex.left = cur.right;
  161.     if (vertex.left != this.#nil) {
  162.       vertex.left.parent = vertex;
  163.     }
  164.     vertex.parent = cur;
  165.     cur.right = vertex;
  166.     if (vertex == this.#root) {
  167.       this.#root = cur;
  168.       this.#root.parent = this.#nil;
  169.     }
  170.   }
  171.  
  172.   /** #flipLeft() credit: Morin 9.2.2.
  173.    * @param {Vertex} vertex vertex to flip left
  174.    */
  175.   #flipLeft(vertex) {
  176.     this.#swapColors(vertex, vertex.right);
  177.     this.#rotateLeft(vertex);
  178.   }
  179.  
  180.   /** #flipRight() credit: Morin 9.2.2.
  181.    * @param {Vertex} vertex vertex to flip right
  182.    */
  183.   #flipRight(vertex) {
  184.     this.#swapColors(vertex, vertex.left);
  185.     this.#rotateRight(vertex);
  186.   }
  187.  
  188.   /** #addFixup() credit: Morin 9.2.3.
  189.    * @param {Vertex} vertex vertex to fix-up for add
  190.    */
  191.   #addFixup(vertex) {
  192.     while (vertex.color == red) {
  193.       if (vertex == this.#root) {  // vertex is the root = done
  194.         vertex.color = black;
  195.         return;
  196.       }
  197.       var cur = vertex.parent;
  198.       if (cur.left.color == black) {  // ensure left-leaning
  199.         this.#flipLeft(cur);
  200.         vertex = cur;
  201.         cur = vertex.parent;
  202.       }
  203.       if (cur.color == black) {
  204.         return;  // no red-red edge = done
  205.       }
  206.       var gP = cur.parent;  // grandparent of vertex
  207.       if (gP.right.color == black) {
  208.         this.#flipRight(gP);
  209.         return;
  210.       } else {
  211.         this.#pushBlack(gP);
  212.         vertex = gP;
  213.       }
  214.     }
  215.   }
  216.  
  217.   /** #findLast() credit: Morin 6.2.2.
  218.    * @param {any} value value for comparison
  219.    * @returns {Vertex} last vertex found on path for value
  220.    */
  221.   #findLast(value) {
  222.     var cur = this.#root, prev = this.#nil;
  223.     while (cur != this.#nil) {
  224.       prev = cur;
  225.       var res = this.#compare(value, cur.value);
  226.       if (res < 0) { cur = cur.left; }
  227.       else if (res > 0) { cur = cur.right; }
  228.       else { return cur; }
  229.     }
  230.     return prev;
  231.   }
  232.  
  233.   /** #addChild() credit: Morin 6.2.2.
  234.    * @param {Vertex} prev last vertex encountered
  235.    * @param {Vertex} vertex vertex to add
  236.    * @returns {boolean} success?
  237.    */
  238.   #addChild(prev, vertex) {
  239.     if (prev == this.#nil) {
  240.       this.#root = vertex;  // inserting into empty tree
  241.     } else {
  242.       var res = this.#compare(vertex.value, prev.value);
  243.       if (res < 0) {
  244.         prev.left = vertex;
  245.       } else if (res > 0) {
  246.         prev.right = vertex;
  247.       } else {
  248.         return false;  // vertex.value is already in the tree
  249.       }
  250.       vertex.parent = prev;
  251.     }
  252.     this.#numV++;
  253.     return true;
  254.   }
  255.  
  256.   /** #addVertex() credit: Morin BinarySearchTree.java.
  257.    * @param {Vertex} vertex vertex to add
  258.    * @returns {boolean} success?
  259.    */
  260.   #addVertex(vertex) {
  261.     var prev = this.#findLast(vertex.value);
  262.     return this.#addChild(prev, vertex);
  263.   }
  264.  
  265.   /** add() credit: Morin 9.2.3.
  266.    * @param {any} value value to add
  267.    * @returns {boolean} success?
  268.    */
  269.   add(value) {
  270.     var vertex = this.#newVertex(value);
  271.     vertex.color = red;
  272.     var res = this.#addVertex(vertex);
  273.     if (res) { this.#addFixup(vertex); }
  274.     return res;
  275.   }
  276.  
  277.   /** #splice() credit: Morin 6.2.3.
  278.    * @param {Vertex} vertex vertex to splice
  279.    */
  280.   #splice(vertex) {
  281.     var cur, prev;
  282.     if (vertex.left != this.#nil) {
  283.       cur = vertex.left;
  284.     } else {
  285.       cur = vertex.right;
  286.     }
  287.     if (vertex == this.#root) {
  288.       this.#root = cur;
  289.       prev = this.#nil;
  290.     } else {
  291.       prev = vertex.parent;
  292.       if (prev.left == vertex) {
  293.         prev.left = cur;
  294.       } else {
  295.         prev.right = cur;
  296.       }
  297.     }
  298.     if (cur != this.#nil) {
  299.       cur.parent = prev;
  300.     }
  301.     this.#numV--;
  302.   }
  303.  
  304.   /** #removeFixupCase1() credit: Morin 9.2.4.
  305.    * @param {Vertex} vertex vertex to fix-up for remove
  306.    * @returns {Vertex} fixed-up vertex
  307.    */
  308.   #removeFixupCase1(vertex) {
  309.     this.#flipRight(vertex.parent);
  310.     return vertex;
  311.   }
  312.  
  313.   /** #removeFixupCase2() credit: Morin 9.2.4.
  314.    * @param {Vertex} vertex vertex to fix-up for remove
  315.    * @returns {Vertex} fixed-up vertex
  316.    */
  317.   #removeFixupCase2(vertex) {
  318.     var w = vertex.parent;
  319.     var v = w.right;
  320.     this.#pullBlack(w);  // w.left
  321.     this.#flipLeft(w);  // w is now red
  322.     var q = w.right;
  323.     if (q.color == red) {  // q-w is red-red
  324.       this.#rotateLeft(w);
  325.       this.#flipRight(v);
  326.       this.#pushBlack(q);
  327.       if (v.right.color == red) {
  328.         this.#flipLeft(v);
  329.       }
  330.       return q;
  331.     } else {
  332.       return v;
  333.     }
  334.   }
  335.  
  336.   /** #removeFixupCase3() credit: Morin 9.2.4.
  337.    * @param {Vertex} vertex vertex to fix-up for remove
  338.    * @returns {Vertex} fixed-up vertex
  339.    */
  340.   #removeFixupCase3(vertex) {
  341.     var w = vertex.parent;
  342.     var v = w.left;
  343.     this.#pullBlack(w);
  344.     this.#flipRight(w);  // w is now red
  345.     var q = w.left;
  346.     if (q.color == red) {  // q-w is red-red
  347.       this.#rotateRight(w);
  348.       this.#flipLeft(v);
  349.       this.#pushBlack(q);
  350.       return q;
  351.     } else {
  352.       if (v.left.color == red) {
  353.         this.#pushBlack(v);  // both v's children are red
  354.         return v;
  355.       } else {  // ensure left-leaning
  356.         this.#flipLeft(v);
  357.         return w;
  358.       }
  359.     }
  360.   }
  361.  
  362.   /** #removeFixup() credit: Morin 9.2.4.
  363.    * @param {Vertex} vertex vertex to fix-up for remove
  364.    */
  365.   #removeFixup(vertex) {
  366.     while (vertex.color > black) {
  367.       if (vertex == this.#root) {
  368.         vertex.color = black;
  369.       } else if (vertex.parent.left.color == red) {
  370.         vertex = this.#removeFixupCase1(vertex);
  371.       } else if (vertex == vertex.parent.left) {
  372.         vertex = this.#removeFixupCase2(vertex);
  373.       } else {
  374.         vertex = this.#removeFixupCase3(vertex);
  375.       }
  376.     }
  377.     if (vertex != this.#root) {  // restore left-leaning property if needed
  378.       var cur = vertex.parent;
  379.       if (cur.right.color == red && cur.left.color == black) {
  380.         this.#flipLeft(cur);
  381.       }
  382.     }
  383.   }
  384.  
  385.   /** remove() credit: Morin 9.2.4.
  386.    * @param {any} value value to remove
  387.    * @returns {boolean} success?
  388.    */
  389.   remove(value) {
  390.     var prev = this.#findLast(value);
  391.     if (prev == this.#nil || this.#compare(prev.value, value) != 0) {
  392.       return false;
  393.     }
  394.     var cur = prev.right;
  395.     if (cur == this.#nil) {
  396.       cur = prev;
  397.       prev = cur.left;
  398.     } else {
  399.       while (cur.left != this.#nil) {
  400.         cur = cur.left;
  401.       }
  402.       prev.value = cur.value;
  403.       prev = cur.right;
  404.     }
  405.     this.#splice(cur);
  406.     prev.color += cur.color;
  407.     prev.parent = cur.parent;
  408.     this.#removeFixup(prev);
  409.     return true;
  410.   }
  411.  
  412.   /** findEQ() Find an equal value. credit: Morin 6.2.1.
  413.    * @param {any} value value to find
  414.    * @returns {any} value if found, undefined if not found
  415.    */
  416.   findEQ(value) {
  417.     var cur = this.#root;
  418.     while (cur != this.#nil) {
  419.       var res = this.#compare(value, cur.value);
  420.       if (res < 0) { cur = cur.left; }
  421.       else if (res > 0) { cur = cur.right; }
  422.       else { return cur.value; }
  423.     }
  424.     return undefined;
  425.   }
  426.  
  427.   /** #findGEVertex() credit: Morin BinarySearchTree.java.
  428.    * @param {any} value value to find
  429.    * @returns {Vertex} last vertex found on path for value
  430.    */
  431.   #findGEVertex(value) {
  432.     var cur = this.#root, last = this.#nil;
  433.     while (cur != this.#nil) {
  434.       var res = this.#compare(value, cur.value);
  435.       if (res < 0) {
  436.         last = cur;
  437.         cur = cur.left;
  438.       } else if (res > 0) {
  439.         cur = cur.right;
  440.       } else {
  441.         return cur;
  442.       }
  443.     }
  444.     return last;
  445.   }
  446.  
  447.   /** findGE() Find smallest value in tree greater than or equal to given value, or undefined
  448.    * if no such value. Or, if given value is undefined then the smallest value in tree.
  449.    * credit: Morin BinarySearchTree.java, SSet.java.
  450.    * @param {any} value value to find
  451.    * @returns {any} smallest value in tree greater than or equal to given value, or undefined if no
  452.    *               such value. Or, if given value is undefined then the smallest value in tree.
  453.    */
  454.   findGE(value) {
  455.     if (value == undefined) {  // find the minimum value
  456.       var cur = this.#root;
  457.       if (cur == this.#nil) { return undefined; }
  458.       while (cur.left != this.#nil) {
  459.         cur = cur.left;
  460.       }
  461.       return cur.value;
  462.     }
  463.     var cur = this.#findGEVertex(value);
  464.     if (cur == this.#nil) { return undefined; }
  465.     return cur.value;
  466.   }
  467.  
  468.   /** #findLEVertex() credit: Morin BinarySearchTree.java.
  469.    * @param {any} value value to find
  470.    * @returns {Vertex} last vertex found on path for value
  471.    */
  472.   #findLEVertex(value) {
  473.     var cur = this.#root, last = this.#nil;
  474.     while (cur != this.#nil) {
  475.       var res = this.#compare(value, cur.value);
  476.       if (res < 0) {
  477.         cur = cur.left;
  478.       } else if (res > 0) {
  479.         last = cur;
  480.         cur = cur.right;
  481.       } else {
  482.         return cur;
  483.       }
  484.     }
  485.     return last;
  486.   }
  487.  
  488.   /** findLE() Find largest value in tree less than or equal to given value, or undefined
  489.    * if no such value. Or, if given value is undefined then the largest value in tree.
  490.    * credit: Morin BinarySearchTree.java findLT [sic].
  491.    * @param {any} value value to find
  492.    * @returns {any} largest value in tree less than or equal to given value, or undefined if no
  493.    *               such value. Or, if given value is undefined then the largest value in tree.
  494.    */
  495.   findLE(value) {
  496.     if (value == undefined) {  // find the maximum value
  497.       var cur = this.#root;
  498.       if (cur == this.#nil) { return undefined; }
  499.       while (cur.right != this.#nil) {
  500.         cur = cur.right;
  501.       }
  502.       return cur.value;
  503.     }
  504.     var cur = this.#findLEVertex(value);
  505.     if (cur == this.#nil) { return undefined; }
  506.     return cur.value;
  507.   }
  508.  
  509.   /** #depth() Get vertex depth. credit: Morin 6.1.
  510.    * @param {Vertex} vertex vertex to calculate depth for
  511.    * @returns {number} depth of given vertex
  512.    */
  513.   #depth(vertex) {
  514.     var count = 0;
  515.     while (vertex != this.#root) {
  516.       vertex = vertex.parent;
  517.       count++;
  518.     }
  519.     return count;
  520.   }
  521.  
  522.   /** #sizeOfV() Get vertex size. credit: Morin 6.1.1.
  523.    * @param {Vertex} vertex vertex to calculate size for
  524.    * @returns {number} size of given vertex
  525.    */
  526.   #sizeOfV(vertex) {
  527.     if (vertex == this.#nil) { return 0; }
  528.     return 1 + this.#sizeOfV(vertex.left) + this.#sizeOfV(vertex.right);
  529.   }
  530.  
  531.   /** size3() Get tree size.
  532.    * @returns {number} size of tree
  533.    */
  534.   size3() {
  535.     return this.#sizeOfV(this.#root);
  536.   }
  537.  
  538.   /** #verifyVertex() credit: Morin RedBlackTree.java.
  539.    * @param {Vertex} vertex vertex to verify
  540.    * @returns {number} black height of vertex
  541.    */
  542.   #verifyVertex(vertex) {
  543.     if (vertex == this.#nil) {
  544.       return vertex.color;
  545.     }
  546.     if (vertex.color < red || vertex.color > black) {
  547.       throw new Error("verify: invalid color = " + vertex.color);
  548.     }
  549.     if (vertex.color == red) {
  550.       if (vertex.left.color == red || vertex.right.color == red) {
  551.         throw new Error("verify: red-red edge found");
  552.       }
  553.     }
  554.     if (vertex.right.color == red && vertex.left.color != red) {
  555.       throw new Error("verify: non-left-leaning vertex found");
  556.     }
  557.     var depthL = this.#verifyVertex(vertex.left);
  558.     var depthR = this.#verifyVertex(vertex.right);
  559.     if (depthL != depthR) {
  560.       throw new Error("verify: black-height property violated");
  561.     }
  562.     return depthL + vertex.color;
  563.   }
  564.  
  565.   /** verify() credit: Morin RedBlackTree.java. */
  566.   verify() {
  567.     if (this.#sizeOfV(this.#root) != this.#numV) {
  568.       throw new Error("verify: size is incorrect");
  569.     }
  570.     this.#verifyVertex(this.#root);
  571.   }
  572.  
  573.   /** size() Get tree size. credit: Morin BinarySearchTree.java.
  574.    * @returns {number} size of tree
  575.    */
  576.   size() {
  577.     return this.#numV;
  578.   }
  579.  
  580.   /** clear() credit: Morin BinaryTree.java, BinarySearchTree.java. */
  581.   clear() {
  582.     this.#root = this.#nil;
  583.     this.#numV = 0;
  584.   }
  585.  
  586.   /** #heightOfV() Get vertex height. credit: Morin 6.1.1.
  587.    * @param {Vertex} vertex vertex to calculate height for
  588.    * @returns {number} height of given vertex, or -1 if nil vertex
  589.    */
  590.   #heightOfV(vertex) {
  591.     if (vertex == this.#nil) { return -1; }
  592.     return 1 + Math.max(this.#heightOfV(vertex.left), this.#heightOfV(vertex.right));
  593.   }
  594.  
  595.   /** height() Get tree height.
  596.    * @returns {number} height of root, or -1 if nil root
  597.    */
  598.   height() {
  599.     return this.#heightOfV(this.#root);
  600.   }
  601.  
  602.   /** #formatVertices()
  603.    * @param {boolean} flag if true, append additional vertex info
  604.    * @param {Vertex[]} vertices vertices in this tree
  605.    * @returns {string} vertices formatted as tree
  606.    */
  607.   #formatVertices(flag, vertices) {
  608.     var retVertices = "";
  609.     for (var i = 0; i < vertices.length; i++) {
  610.       retVertices += '\n' + " ".repeat(this.#depth(vertices[i]) + 1) + vertices[i].value;
  611.       if (flag) {
  612.         var height = this.#heightOfV(vertices[i]);
  613.         var size = this.#sizeOfV(vertices[i]);
  614.         retVertices += "  height=" + height + "  size=" + size;
  615.         if (vertices[i].parent != this.#nil) {
  616.           retVertices += "  parent=" + vertices[i].parent.value;
  617.         }
  618.       }
  619.     }
  620.     return retVertices;
  621.   }
  622.  
  623.   /** #traverseInner() Inner depth-first traverse. credit: Morin 6.1.2.
  624.    * @param {Vertex} vertex vertex to traverse
  625.    * @param {Vertex[]} dfVertices discovered vertices
  626.    */
  627.   #traverseInner(vertex, dfVertices) {
  628.     if (vertex == this.#nil) { return; }
  629.     vertex.bSeen = true;
  630.     if (!vertex.left.bSeen) {
  631.       vertex.left.bSeen = true;
  632.       this.#traverseInner(vertex.left, dfVertices);
  633.     }
  634.     if (!vertex.right.bSeen) {
  635.       vertex.right.bSeen = true;
  636.       this.#traverseInner(vertex.right, dfVertices);
  637.     }
  638.     dfVertices.unshift(vertex);
  639.   }
  640.  
  641.   /** traverse() Depth-first traverse.
  642.    * @returns {string} vertices formatted as tree
  643.    */
  644.   traverse() {
  645.     var dfVertices = [];
  646.     this.#traverseInner(this.#root, dfVertices);
  647.     this.bfTraverse(false);
  648.     return "depth-first traverse" + this.#formatVertices(false, dfVertices);
  649.   }
  650.  
  651.   /** traverse2() Depth-first traverse. credit: Morin 6.1.2.
  652.    * @returns {string} vertices formatted as tree
  653.    */
  654.   traverse2() {
  655.     var dfVertices = [];
  656.     var cur = this.#root, prev = this.#nil, next;
  657.     while (cur != this.#nil) {
  658.       if (prev == cur.parent) {
  659.         if (cur.left != this.#nil) { next = cur.left; }
  660.         else if (cur.right != this.#nil) { next = cur.right; }
  661.         else { next = cur.parent; }
  662.       } else if (prev == cur.left) {
  663.         if (cur.right != this.#nil) { next = cur.right; }
  664.         else { next = cur.parent; }
  665.       } else {
  666.         next = cur.parent;
  667.       }
  668.       prev = cur;
  669.       if (!cur.bSeen) {
  670.         dfVertices.push(cur);
  671.         cur.bSeen = true;
  672.       }
  673.       cur = next;
  674.     }
  675.     this.bfTraverse(false);
  676.     return "depth-first traverse #2" + this.#formatVertices(false, dfVertices);
  677.   }
  678.  
  679.   /** bfTraverse() Breadth-first traverse. credit: Morin 6.1.2.
  680.    * @param {boolean} flag true: set bSeen, false: unset bSeen
  681.    * @returns {string} vertices formatted as tree
  682.    */
  683.   bfTraverse(flag) {
  684.     var bfVertices = [];
  685.     var queue = [];  // queue of Vertex's
  686.     if (this.#root != this.#nil) {
  687.       queue.push(this.#root);
  688.       this.#root.bSeen = flag;
  689.     }
  690.     while (queue.length > 0) {
  691.       var vertex = queue.shift();
  692.       if (flag) { bfVertices.push(vertex); }
  693.       if (vertex.left != this.#nil) {
  694.         if (flag) {
  695.           if (!vertex.left.bSeen) {
  696.             queue.push(vertex.left);
  697.             vertex.left.bSeen = flag;
  698.           }
  699.         } else {
  700.           queue.push(vertex.left);
  701.           vertex.left.bSeen = flag;
  702.         }
  703.       }
  704.       if (vertex.right != this.#nil) {
  705.         if (flag) {
  706.           if (!vertex.right.bSeen) {
  707.             queue.push(vertex.right);
  708.             vertex.right.bSeen = flag;
  709.           }
  710.         } else {
  711.           queue.push(vertex.right);
  712.           vertex.right.bSeen = flag;
  713.         }
  714.       }
  715.     }
  716.     if (flag) { this.bfTraverse(false); }
  717.     return "breadth-first traverse" + this.#formatVertices(true, bfVertices);
  718.   }
  719.  
  720.   /** size2() Get tree size. credit: Morin 6.1.2.
  721.    * @returns {number} size of tree
  722.    */
  723.   size2() {
  724.     var cur = this.#root, prev = this.#nil, next;
  725.     var count = 0;
  726.     while (cur != this.#nil) {
  727.       if (prev == cur.parent) {
  728.         count++;
  729.         if (cur.left != this.#nil) { next = cur.left; }
  730.         else if (cur.right != this.#nil) { next = cur.right; }
  731.         else { next = cur.parent; }
  732.       } else if (prev == cur.left) {
  733.         if (cur.right != this.#nil) { next = cur.right; }
  734.         else { next = cur.parent; }
  735.       } else {
  736.         next = cur.parent;
  737.       }
  738.       prev = cur;
  739.       cur = next;
  740.     }
  741.     return count;
  742.   }
  743. }
  744.  
  745. /** compare() Compare values. This will work for string and number types.
  746.  * @param {any} a a value
  747.  * @param {any} b another value
  748.  * @returns {number} -1 if a < b, 0 if a == b, 1 if a > b
  749.  */
  750. function compare(a, b) {
  751.   if (a < b) { return -1; }
  752.   else if (a > b) { return 1; }
  753.   return 0;
  754. }
  755.  
  756. /** assertSets() Assert that sizes and values of tree and set are equal.
  757.  * @param {RedBlackTree} aTree a tree
  758.  * @param {Set} aSet a set
  759.  */
  760. function assertSets(aTree, aSet) {
  761.   if (aTree.size() == aSet.size) {
  762.     var i = 0, setVals = Array.from(aSet).sort(compare);
  763.     for (const tVal of aTree) {
  764.       if (compare(tVal, setVals[i]) != 0) {
  765.         throw new Error("assert: value mismatch");
  766.       }
  767.       i++;
  768.     }
  769.   } else {
  770.     throw new Error("assert: size mismatch");
  771.   }
  772. }
  773.  
  774.  
  775. var natoValues = ["alpha", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
  776.                   "india", "juliet", "kilo", "lima", "mike", "november", "oscar", "papa",
  777.                   "quebec", "romeo", "sierra", "tango"];
  778. var wuValues = ["adams", "boston", "chicago", "denver", "easy", "frank", "george", "henry",
  779.                 "ida", "john", "king", "lincoln", "mary", "new york", "ocean", "peter",
  780.                 "queen", "roger", "sugar", "thomas"];
  781. var rbTree = new RedBlackTree(compare);
  782. var valuesSet = new Set();
  783.  
  784. for (var i = 0; i < natoValues.length; i++) {
  785.   rbTree.add(natoValues[i]);
  786.   valuesSet.add(natoValues[i]);
  787. }
  788. console.log("--added " + natoValues.length + " nato phonetics--");
  789. rbTree.verify();
  790. assertSets(rbTree, valuesSet);
  791.  
  792. console.log(rbTree.traverse());
  793.  
  794. console.log("findEQ(" + JSON.stringify(wuValues[0]) + ") = " + rbTree.findEQ(wuValues[0]));
  795. console.log("findGE(" + JSON.stringify(wuValues[0]) + ") = " + rbTree.findGE(wuValues[0]));
  796. console.log("findEQ(" + JSON.stringify(natoValues[0]) + ") = " + rbTree.findEQ(natoValues[0]));
  797. console.log("size = " + rbTree.size());
  798.  
  799. for (var i = wuValues.length - 1; i >= 0; i--) {
  800.   rbTree.add(wuValues[i]);
  801.   valuesSet.add(wuValues[i]);
  802. }
  803. console.log("--added (in reverse order) " + wuValues.length + " western union phonetics--");
  804. rbTree.verify();
  805. assertSets(rbTree, valuesSet);
  806.  
  807. console.log(rbTree.traverse());
  808.  
  809. console.log("findEQ(" + JSON.stringify(wuValues[0]) + ") = " + rbTree.findEQ(wuValues[0]));
  810. console.log("findLE(" + JSON.stringify(natoValues[0]) + ") = " + rbTree.findLE(natoValues[0]));
  811. console.log("minimum = " + rbTree.findGE(undefined) + ", maximum = " + rbTree.findLE(undefined));
  812. console.log("size = " + rbTree.size() + ", size #2 = " + rbTree.size2() + ", size #3 = " + rbTree.size3());
  813. console.log("height = " + rbTree.height());
  814.  
  815. for (var i = 0; i < natoValues.length / 2; i++) {
  816.   rbTree.remove(natoValues[i]);
  817.   valuesSet.delete(natoValues[i]);
  818. }
  819. console.log("--removed first " + (natoValues.length / 2) + " nato phonetics--");
  820. rbTree.verify();
  821. assertSets(rbTree, valuesSet);
  822.  
  823. console.log(rbTree.traverse2());
  824.  
  825. console.log("findEQ(" + JSON.stringify(natoValues[0]) + ") = " + rbTree.findEQ(natoValues[0]));
  826. var ndxLast = natoValues.length / 2 - 1;
  827. console.log("findLE(" + JSON.stringify(natoValues[ndxLast]) + ") = " + rbTree.findLE(natoValues[ndxLast]));
  828. console.log("findGE(" + JSON.stringify(natoValues[0]) + ") = " + rbTree.findGE(natoValues[0]));
  829.  
  830. console.log(rbTree.bfTraverse(true));
  831.  
  832. console.log("toString = " + rbTree.toString());
  833. rbTree.clear();
  834. valuesSet.clear();
  835. console.log("--clear--");
  836. console.log("toString = " + rbTree.toString());
  837.  
  838. /** @version 1.0 */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement