UNPKG

vebt

Version:

A Van Emde Boas tree, also known as a vEB tree, is a tree data structure which implements an associative array with k-bit integer keys. It performs all operations in O(log k) time, or equivalently in O(log log K) time, where K = 2^k is the maximum number

242 lines (218 loc) 5.39 kB
//// Shortcuts const {log} = require('./shortcuts.js') //// Van Embe Boas Tree // VEB Tree Constructor -> <VEBT> function VEBT(k){ // Tree Dimension this.k = k // MIN and MAX elements this.min this.max // Children array, consisting of 2^{k/2} k/2-trees this.children = [] } // VEB + AUX сonstructor, with the multiplicity condition 2 -> <VEBT+AUX> function VEBX(k) { // Conditions if(k < 0){ log('VEBX: Dimension must be > 0') return 0 }else{ this.k = 2 while(this.k < k){ this.k *= 2 } } // Main tree let T = new VEBT(this.k) // Auxiliary tree T.aux = new VEBT(this.k/2) return T } // {Find} operation -> <Boolean>: <true> - x exists in <VEBX>, <false> - x doesn't exist in <VEBX> VEBT.prototype.find = function(x){ if(this.empty){ return false } if(this.min == x || this.max == x){ return true } let highx = this.high(x) if(this.children[highx]){ return this.children[highx].find(this.low(x)) }else{ return false } } // {Insert} operation VEBT.prototype.insert = function(x) { // Batch insert if(typeof x == "object"){ for(i in x){ this.insert(x[i]) } return 3 } if(this.empty){ // Empty tree case this.min = x this.max = x }else if(this.min == this.max){ // 1-Tree case if(this.min < x){ this.max = x }else{ this.min = x } }else{ // Over-relaxation of MIN if(this.min > x){ let tmp = x x = this.min this.min = tmp } // Over-relaxation of MAX if(this.max < x){ let tmp = x x = this.max this.max = tmp } // Element insertion if(this.k != 1){ // high(x) to AUX let highx = this.high(x) let node = this.children[highx] if(!node){ this.children[highx] = new VEBX(this.k) } if(this.children[this.high(x)].empty){ if(!this.aux){ this.aux = new VEBT(this.k/2) } this.aux.insert(this.aux.high(x)) } // low(x) to children[high(x)] sub-tree this.children[highx].insert(this.low(x)) } } return 3 } // {Remove} operation -> <Signal>: 4 - removed VEBT.prototype.remove = function(x){ if(this.min == x && this.max == x){ // Case, when only one element left delete this.min return 4 } if(this.min == x){ if(this.aux.empty){ this.min = this.max return 4 } x = this.index(this.aux.min, this.children[this.aux.min].min) this.min = x } if(this.max == x){ if(this.aux.empty){ this.max = this.min return 4 } }else{ x = this.index(this.aux.max, this.children[this.aux.max].max) this.max = x } if(this.aux.empty){ return 0 } // Cascade remove this.children[this.high(x)].remove(this.low(x)) // If we removed the last element from the subtree, then we delete the information that this subtree is not empty if(this.children[this.high(x)].empty){ this.aux.remove(this.high(x)) } } // {FindNext} operation VEBT.prototype.next = function(x){ // Empty Tree and ending cases if(this.empty || this.max <= x){ return undefined } if(this.min > x){ return this.min } // Tree has no more than two elements if(this.aux && this.aux.empty){ return this.max }else{ // Case where the next number begins with high(x) let highx = this.children[this.high(x)] if(highx && !highx.empty && highx.max > this.low(x)){ return this.index(this.high(x), this.children[this.high(x)].next(this.low(x))) // Otherwise we should find next non-empty subtree }else if(this.aux){ let nextHigh = this.aux.next(this.aux.high(x)) if(!nextHigh || !this.children[nextHigh]){ return this.max }else{ return this.index(nextHigh, this.children[nextHigh].min) } } } } // {FindPrevious} operation VEBT.prototype.prev = function(x){ // Empty Tree and ending cases if(this.empty || this.min >= x){ return undefined } if(this.max < x){ return this.max } // Tree has no more than two elements if(this.aux && this.aux.empty){ return this.min }else{ // Case where the next number begins with high(x) let highx = this.children[this.high(x)] if(highx && !highx.empty && highx.min < this.low(x)){ return this.index(this.high(x), this.children[this.high(x)].prev(this.low(x))) // Otherwise we should find next non-empty subtree }else if(this.aux){ let nextHigh = this.aux.next(this.aux.high(x)) if(!nextHigh || !this.children[nextHigh]){ return this.min }else{ return this.index(nextHigh, this.children[nextHigh].max) } } } } /// VEBT Utilites // Is tree empty? Object.defineProperty(VEBT.prototype, 'empty', { get: function(){ return this.min == undefined ? true : false } }) // Highest VEBT.high = function(x) { return Math.floor(x / Math.sqrt(this.k)) } VEBT.prototype.high = VEBT.high // Lowest VEBT.low = function(x) { return x % Math.ceil(Math.sqrt(this.k)) } VEBT.prototype.low = VEBT.low // Index VEBT.index = function(x, y) { return (x * Math.floor(Math.sqrt(this.k))) + y } VEBT.prototype.index = VEBT.index // Calculate safe tree dimension VEBT.offerK = function(x) { if(typeof x == 'object'){ x = Math.max(...x) } return Math.pow(2, (Math.log(x) * Math.LOG10E + 1 | 0) * 8) } VEBT.prototype.offerK = VEBT.offerK //// Exports module.exports = {VEBT, VEBX}