UNPKG

priority-deque

Version:

A double-ended priority queue based on min-max heaps.

69 lines 5.12 kB
"use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PriorityDeque=void 0;const floyd_rivest_1=require("floyd-rivest");var CMP;(function(CMP){CMP[CMP["LT"]=-1]="LT";CMP[CMP["EQ"]=0]="EQ";CMP[CMP["GT"]=1]="GT";})(CMP||(CMP={}));const defaultComp=(a,b)=>{return(typeof a==='number')?(a-(+b))||0:(""+a).localeCompare(""+b);};function isMinLevel(i){return(Math.log2(i+1)&1)===0;} function extremalDescendant(h,compare,i,C){const len=h.length;const lc=(i<<1)+1;if(lc>=len){return-1;} const rc=lc+1;if(rc>=len){return lc;} let m=Math.sign(compare(h[rc],h[lc]))===C?rc:lc;let gc=(i<<2)+3;const end=Math.min(gc+4,len);for(;gc<end;gc++){if(Math.sign(compare(h[gc],h[m]))===C){m=gc;}} return m;} class PriorityDeque{constructor(opts={}){this.heap=[];this.limit=Infinity;this.compare=defaultComp;if(typeof opts.compare==='function'){this.compare=opts.compare;} if(typeof opts.limit==='number'){this.limit=opts.limit;} if(opts.items&&typeof opts.items[Symbol.iterator]==='function'){this.set(opts.items);}} clone(){const pd=new PriorityDeque({compare:this.compare,limit:this.limit,});pd.heap=[...this.heap];return pd;} reheap(i){for(;i>=0;i--){this.trickleDown(i);}} set(elements){const items=[...elements];const{limit}=this;if(items.length>limit){floyd_rivest_1.select(items,limit,(a,b)=>Math.sign(this.compare(a,b)));items.length=limit;} this.heap=items;this.reheap(items.length>>1);} clear(){this.heap.length=0;} trickleDown(i){const{heap:h,compare}=this;let C=isMinLevel(i)?CMP.LT:CMP.GT;for(;;){const m=extremalDescendant(h,compare,i,C);if(m===-1){return;} const hi=h[i];const hm=h[m];if(Math.sign(compare(hm,hi))===C){h[i]=hm;h[m]=hi;if(m>((i+1)<<1)){const parent=(m-1)>>1;const hp=h[parent];if(Math.sign(compare(hp,hi))===C){h[m]=hp;h[parent]=hi;}} else{C=-C;} i=m;} else{break;}}} bubbleUp(i){const{heap,compare}=this;const p=(i-1)>>1;const hi=heap[i];const hp=heap[p];const cmp=Math.sign(compare(hi,hp));let moved=false;let LT=CMP.LT;if(isMinLevel(i)){if(cmp===CMP.GT){heap[i]=hp;heap[p]=hi;i=p;LT=CMP.GT;moved=true;}} else if(cmp===CMP.LT){heap[i]=hp;heap[p]=hi;i=p;moved=true;} else{LT=CMP.GT;} while(i>=3){const gp=(((i-1)>>1)-1)>>1;const hi=heap[i];const hp=heap[gp];if(Math.sign(compare(hi,hp))===LT){heap[i]=hp;heap[gp]=hi;i=gp;moved=true;} else break;} return moved;} [Symbol.iterator](){return this.heap.values();} get length(){return this.heap.length;} push(...elements){this.append(elements);} append(elements){if(this.limit===0) return;if(elements.length===0) return;const{heap,compare,limit}=this;let size=heap.length;const l=elements.length;const addable=Math.min(limit-size,l);let i=0;if(size===0){heap[0]=elements[0];size=1;i=1;} for(;i<addable;i++,size++){this.heap[size]=elements[i];this.bubbleUp(size);} if(limit===1){for(;i<l;i++){const e=elements[i];if(Math.sign(compare(e,heap[0]))===CMP.LT){heap[0]=e;}}} else{let maxI=this.maxIndex();let maxE=heap[maxI];for(;i<l;i++){const e=elements[i];if(Math.sign(compare(e,maxE))!==CMP.LT){continue;} heap[maxI]=e;if(!this.bubbleUp(maxI)){this.trickleDown(maxI);} maxI=this.maxIndex();maxE=heap[maxI];}}} pop(){if(this.heap.length===0){return undefined;} return this.removeAt(0);} shift(){if(this.heap.length===0){return undefined;} return this.removeAt(this.maxIndex());} unshift(...elements){this.append(elements);} map(fn,compare=defaultComp){const pd=new PriorityDeque({compare,limit:this.limit});pd.heap=this.heap.map(fn);pd.reheap(this.heap.length>>1);return pd;} filter(fn){const pd=new PriorityDeque({compare:this.compare,limit:this.limit,});pd.heap=this.heap.filter(fn);pd.reheap(pd.heap.length>>1);return pd;} collect(fn,compare=defaultComp){const pd=new PriorityDeque({compare,limit:this.limit});const heap=[];let l=0;for(const e of this.heap){for(const v of fn(e)){heap[l++]=v;}} pd.heap=heap;pd.reheap(l>>1);return pd;} contains(e){return this.heap.indexOf(e)>-1;} some(fn){return this.heap.some(fn);} every(fn){return this.heap.every(fn);} find(fn){return this.heap.find(fn);} forEach(fn){this.heap.forEach(fn);} findMin(){return this.heap.length>0?this.heap[0]:undefined;} findMax(){return this.heap.length>0?this.heap[this.maxIndex()]:undefined;} maxIndex(){const{heap}=this;if(heap.length<2){return 0;} if(heap.length===2){return 1;} return Math.sign(this.compare(heap[1],heap[2]))===CMP.LT?2:1;} replaceMin(e){if(this.limit===0){return undefined;} const{heap}=this;let size=heap.length;const minE=heap[0];heap[0]=e;if(size>0){this.trickleDown(0);} return minE;} replaceMax(e){if(this.limit===0){return undefined;} const{heap}=this;const maxI=this.maxIndex();const maxE=heap[maxI];heap[maxI]=e;if(maxI>0&&!this.bubbleUp(maxI)){this.trickleDown(maxI);} return maxE;} removeAt(i){const{heap}=this;const ret=heap[i];const size=heap.length-1;if(size>0){heap[i]=heap[size];this.trickleDown(i);} heap.length=size;return ret;} remove(e){const{heap}=this;const i=heap.indexOf(e);if(i===-1){return false;} this.removeAt(i);return true;} replace(a,b){const{heap}=this;const i=heap.indexOf(a);if(i===-1){return false;} heap[i]=b;if(i===0||!this.bubbleUp(i)){this.trickleDown(i);} return true;}} exports.PriorityDeque=PriorityDeque;