1 | export class Heap {
|
2 | constructor() {
|
3 | this.container = [];
|
4 | }
|
5 | get Size() {
|
6 | return this.container.length;
|
7 | }
|
8 | getLeftChildIndex(parent) {
|
9 | return (2 * parent) + 1;
|
10 | }
|
11 | getRigthChildIndex(parent) {
|
12 | return (2 * parent) + 2;
|
13 | }
|
14 | getParentIndex(index) {
|
15 | return Math.floor((index - 1) / 2);
|
16 | }
|
17 | getLeftChild(parent) {
|
18 | return this.container[this.getLeftChildIndex(parent)];
|
19 | }
|
20 | getRightChild(parent) {
|
21 | return this.container[this.getRigthChildIndex(parent)];
|
22 | }
|
23 | getParent(index) {
|
24 | return this.container[this.getParentIndex(index)];
|
25 | }
|
26 | hasLeftChild(parent) {
|
27 | return this.getLeftChildIndex(parent) < this.container.length;
|
28 | }
|
29 | hasRightChild(parent) {
|
30 | return this.getRigthChildIndex(parent) < this.container.length;
|
31 | }
|
32 | hasParent(index) {
|
33 | return this.getParentIndex(index) >= 0;
|
34 | }
|
35 | swap(indexOne, indexTwo) {
|
36 | const temp = this.container[indexTwo];
|
37 | this.container[indexTwo] = this.container[indexOne];
|
38 | this.container[indexOne] = temp;
|
39 | }
|
40 | heapifyUp(customStartIndex) {
|
41 | let currentIndex = customStartIndex || this.container.length - 1;
|
42 | while (this.hasParent(currentIndex) && !this.compare(this.getParent(currentIndex), this.container[currentIndex])) {
|
43 | this.swap(currentIndex, this.getParentIndex(currentIndex));
|
44 | currentIndex = this.getParentIndex(currentIndex);
|
45 | }
|
46 | }
|
47 | heapifyDown(customStartIndex) {
|
48 | let currentIndex = customStartIndex || 0;
|
49 | let nextIndex = null;
|
50 | while (this.hasLeftChild(currentIndex)) {
|
51 | if (this.hasRightChild(currentIndex)
|
52 | && this.compare(this.getRightChild(currentIndex), this.getLeftChild(currentIndex))) {
|
53 | nextIndex = this.getRigthChildIndex(currentIndex);
|
54 | }
|
55 | else {
|
56 | nextIndex = this.getLeftChildIndex(currentIndex);
|
57 | }
|
58 | if (this.compare(this.container[currentIndex], this.container[nextIndex])) {
|
59 | break;
|
60 | }
|
61 | this.swap(currentIndex, nextIndex);
|
62 | currentIndex = nextIndex;
|
63 | }
|
64 | }
|
65 | poll() {
|
66 | if (this.container.length === 0) {
|
67 | return null;
|
68 | }
|
69 | if (this.container.length === 1) {
|
70 | return this.container.pop();
|
71 | }
|
72 | const item = this.container[0];
|
73 | this.container[0] = this.container.pop();
|
74 | this.heapifyDown();
|
75 | return item;
|
76 | }
|
77 | peek() {
|
78 | if (this.container.length === 0) {
|
79 | return null;
|
80 | }
|
81 | return this.container[0];
|
82 | }
|
83 | add(item) {
|
84 | this.container.push(item);
|
85 | this.heapifyUp();
|
86 | return this;
|
87 | }
|
88 | remove(item) {
|
89 | const numberOfItemsToRemove = this.findAll(item).length;
|
90 | for (let iteration = 0; iteration < numberOfItemsToRemove; iteration += 1) {
|
91 | const indexToRemove = this.findAllIndex(item).pop();
|
92 | if (indexToRemove === (this.container.length - 1)) {
|
93 | this.container.pop();
|
94 | }
|
95 | else {
|
96 | this.container[indexToRemove] = this.container.pop();
|
97 | const parentItem = this.getParent(indexToRemove);
|
98 | if (this.hasLeftChild(indexToRemove) &&
|
99 | (!parentItem || this.compare(parentItem, this.container[indexToRemove]))) {
|
100 | this.heapifyDown(indexToRemove);
|
101 | }
|
102 | else {
|
103 | this.heapifyUp(indexToRemove);
|
104 | }
|
105 | }
|
106 | }
|
107 | return numberOfItemsToRemove > 0;
|
108 | }
|
109 | toString() {
|
110 | return this.container.toString();
|
111 | }
|
112 | isEmpty() {
|
113 | return !this.container.length;
|
114 | }
|
115 | find(arg) {
|
116 | let temp = null;
|
117 | for (let index = 0; index < this.container.length; index++) {
|
118 | const element = this.container[index];
|
119 | const match = typeof arg === "function" ? arg(element) : arg === element;
|
120 | if (match) {
|
121 | temp = element;
|
122 | break;
|
123 | }
|
124 | }
|
125 | return temp;
|
126 | }
|
127 | findAll(arg) {
|
128 | const temp = [];
|
129 | this.container.forEach(item => {
|
130 | const match = typeof arg === "function" ? arg(item) : arg === item;
|
131 | if (match) {
|
132 | temp.push(item);
|
133 | }
|
134 | });
|
135 | return temp;
|
136 | }
|
137 | clear() {
|
138 | this.container.length = 0;
|
139 | }
|
140 | entries() {
|
141 | return [...this.container];
|
142 | }
|
143 | findAllIndex(arg) {
|
144 | const temp = [];
|
145 | this.container.forEach((item, index) => {
|
146 | const match = typeof arg === "function" ? arg(item) : arg === item;
|
147 | if (match) {
|
148 | temp.push(index);
|
149 | }
|
150 | });
|
151 | return temp;
|
152 | }
|
153 | }
|