1 | import { ICompare } from "../interface/ICompare";
|
2 | import { LinkNode } from "../linklist/LinkNode";
|
3 |
|
4 | export interface HeapNode<T>{
|
5 | value: T;
|
6 | degree: number;
|
7 | child ?: LinkNode<HeapNode<T>>;
|
8 | parent ?: LinkNode<HeapNode<T>>;
|
9 | }
|
10 |
|
11 | function compareFn<T>(a: T, b: T){
|
12 | return a <= b;
|
13 | }
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | export class BinomialHeap<T = number>{
|
19 | private head: LinkNode<HeapNode<T>>;
|
20 | private count = 0;
|
21 | constructor(private compare: ICompare<T> = compareFn){
|
22 | }
|
23 |
|
24 | get Count(){
|
25 | return this.count;
|
26 | }
|
27 |
|
28 | get Head(){
|
29 | return this.head;
|
30 | }
|
31 |
|
32 | private setHead(value: T){
|
33 | this.head = new LinkNode<HeapNode<T>>({
|
34 | value,
|
35 | degree: 0,
|
36 | });
|
37 | this.count = 1;
|
38 | }
|
39 |
|
40 | public clear(){
|
41 | this.head = null;
|
42 | this.count = 0;
|
43 | }
|
44 |
|
45 | public isEmpty(){
|
46 | return !this.head;
|
47 | }
|
48 |
|
49 | |
50 |
|
51 |
|
52 |
|
53 | public insert(value: T){
|
54 | |
55 |
|
56 |
|
57 | const heap = new BinomialHeap<T>();
|
58 | heap.setHead(value);
|
59 | const newNode = heap.Head;
|
60 | this.union(heap);
|
61 | return newNode;
|
62 | }
|
63 |
|
64 | |
65 |
|
66 |
|
67 | public deleteExtremum(){
|
68 | if (!this.head){
|
69 | return null;
|
70 | }
|
71 | const deleteNode = this._findExtremum();
|
72 | if (!deleteNode.minPrev){
|
73 | this.head = deleteNode.minNode.Next;
|
74 | }else{
|
75 | deleteNode.minPrev.setNext(deleteNode.minNode.Next);
|
76 | }
|
77 | let child = deleteNode.minNode.Value.child;
|
78 | const newHead = child;
|
79 |
|
80 |
|
81 | while (child){
|
82 | child.Value.parent = null;
|
83 | child = child.Next;
|
84 | }
|
85 | const heap = new BinomialHeap<T>(this.compare);
|
86 | heap.head = newHead;
|
87 |
|
88 | this.union(heap);
|
89 | this.count --;
|
90 | return deleteNode.minNode.Value.value;
|
91 | }
|
92 |
|
93 | |
94 |
|
95 |
|
96 | private _findExtremum(){
|
97 | let next = this.head.Next;
|
98 | let minNode = this.head;
|
99 | let prev: LinkNode<HeapNode<T>> = this.head;
|
100 | let minPrev: LinkNode<HeapNode<T>> = null;
|
101 | let min = minNode.Value.value;
|
102 |
|
103 | while (next){
|
104 | if (!this.compare(min, next.Value.value)){
|
105 | minPrev = prev;
|
106 | minNode = next;
|
107 | min = minNode.Value.value;
|
108 | }
|
109 | prev = next;
|
110 | next = next.Next;
|
111 | }
|
112 | return {minNode, minPrev};
|
113 | }
|
114 |
|
115 | |
116 |
|
117 |
|
118 |
|
119 | public findExtremum(){
|
120 | if (!this.head){
|
121 | return null;
|
122 | }
|
123 | return this._findExtremum().minNode.Value.value;
|
124 | }
|
125 |
|
126 | |
127 |
|
128 |
|
129 |
|
130 | public union(heap: BinomialHeap<T>){
|
131 | |
132 |
|
133 |
|
134 |
|
135 | if (!heap){
|
136 | return this;
|
137 | }
|
138 | this.count += heap.Count;
|
139 | let newHead = this.mergeHeaps(heap);
|
140 | if (!newHead) {
|
141 | return this;
|
142 | }
|
143 | this.head = null;
|
144 | heap.head = null;
|
145 |
|
146 | let prev: LinkNode<HeapNode<T>>;
|
147 | let curr = newHead;
|
148 | let next = newHead.Next;
|
149 | |
150 |
|
151 |
|
152 | while (next){
|
153 |
|
154 | if (next.Value.degree !== curr.Value.degree ||
|
155 | (next.Next && next.Next.Value.degree === curr.Value.degree)){
|
156 | prev = curr;
|
157 | curr = next;
|
158 | }else{
|
159 | if (this.compare( curr.Value.value , next.Value.value)){
|
160 |
|
161 | curr.setNext(next.Next);
|
162 | this.link(curr, next);
|
163 |
|
164 | }else{
|
165 |
|
166 | if (!prev){
|
167 |
|
168 | newHead = next;
|
169 | }else{
|
170 |
|
171 | prev.setNext(next);
|
172 | }
|
173 | this.link(next, curr);
|
174 | curr = next;
|
175 |
|
176 | }
|
177 | }
|
178 |
|
179 | next = curr.Next;
|
180 | }
|
181 | this.head = newHead;
|
182 | return this;
|
183 | }
|
184 |
|
185 | |
186 |
|
187 |
|
188 |
|
189 |
|
190 | private link(tomerge: LinkNode<HeapNode<T>>, frommerge: LinkNode<HeapNode<T>>){
|
191 | frommerge.setNext(tomerge.Value.child);
|
192 | frommerge.Value.parent = tomerge;
|
193 | tomerge.Value.child = frommerge;
|
194 | tomerge.Value.degree ++;
|
195 | }
|
196 |
|
197 | |
198 |
|
199 |
|
200 |
|
201 | private mergeHeaps(heap: BinomialHeap<T>){
|
202 | let thisHead = this.head;
|
203 | let thatHead = heap.Head;
|
204 | if (!thisHead) {
|
205 | return heap.head;
|
206 | }
|
207 | if (!thatHead) {
|
208 | return this.head;
|
209 | }
|
210 | let newHead: LinkNode<HeapNode<T>>;
|
211 |
|
212 | if (thisHead.Value.degree <= thatHead.Value.degree){
|
213 | newHead = this.head;
|
214 | thisHead = thisHead.Next;
|
215 | }else{
|
216 | newHead = heap.head;
|
217 | thatHead = thatHead.Next;
|
218 | }
|
219 | let temp = newHead;
|
220 |
|
221 | while (thisHead && thatHead) {
|
222 | if (thisHead.Value.degree <= thatHead.Value.degree) {
|
223 | temp.setNext(thisHead);
|
224 | thisHead = thisHead.Next;
|
225 | }else{
|
226 | temp.setNext(thatHead);
|
227 | thatHead = thatHead.Next;
|
228 | }
|
229 | temp = temp.Next;
|
230 | }
|
231 | temp.setNext(thisHead ? thisHead : thatHead);
|
232 | return newHead;
|
233 | }
|
234 | }
|