ouija_bh

Scapegoat tree using less memory 0.99b

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