bst-typed 1.53.1 → 1.53.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-structures/heap/heap.d.ts +165 -0
- package/dist/data-structures/heap/heap.js +165 -0
- package/dist/data-structures/linked-list/doubly-linked-list.d.ts +426 -0
- package/dist/data-structures/linked-list/doubly-linked-list.js +430 -2
- package/package.json +2 -2
- package/src/data-structures/heap/heap.ts +165 -0
- package/src/data-structures/linked-list/doubly-linked-list.ts +428 -2
|
@@ -17,6 +17,171 @@ import { IterableElementBase } from '../base';
|
|
|
17
17
|
* 6. Non-linear Search: While a heap allows rapid access to its largest or smallest element, it is less efficient for other operations, such as searching for a specific element, as it is not designed for these tasks.
|
|
18
18
|
* 7. Efficient Sorting Algorithms: For example, heap sort. Heap sort uses the properties of a heap to sort elements.
|
|
19
19
|
* 8. Graph Algorithms: Such as Dijkstra's shortest path algorithm and Prime's minimum-spanning tree algorithm, which use heaps to improve performance.
|
|
20
|
+
* @example
|
|
21
|
+
* // Use Heap to sort an array
|
|
22
|
+
* function heapSort(arr: number[]): number[] {
|
|
23
|
+
* const heap = new Heap<number>(arr, { comparator: (a, b) => a - b });
|
|
24
|
+
* const sorted: number[] = [];
|
|
25
|
+
* while (!heap.isEmpty()) {
|
|
26
|
+
* sorted.push(heap.poll()!); // Poll minimum element
|
|
27
|
+
* }
|
|
28
|
+
* return sorted;
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* const array = [5, 3, 8, 4, 1, 2];
|
|
32
|
+
* console.log(heapSort(array)); // [1, 2, 3, 4, 5, 8]
|
|
33
|
+
* @example
|
|
34
|
+
* // Use Heap to solve top k problems
|
|
35
|
+
* function topKElements(arr: number[], k: number): number[] {
|
|
36
|
+
* const heap = new Heap<number>([], { comparator: (a, b) => b - a }); // Max heap
|
|
37
|
+
* arr.forEach(num => {
|
|
38
|
+
* heap.add(num);
|
|
39
|
+
* if (heap.size > k) heap.poll(); // Keep the heap size at K
|
|
40
|
+
* });
|
|
41
|
+
* return heap.toArray();
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* const numbers = [10, 30, 20, 5, 15, 25];
|
|
45
|
+
* console.log(topKElements(numbers, 3)); // [15, 10, 5]
|
|
46
|
+
* @example
|
|
47
|
+
* // Use Heap to merge sorted sequences
|
|
48
|
+
* function mergeSortedSequences(sequences: number[][]): number[] {
|
|
49
|
+
* const heap = new Heap<{ value: number; seqIndex: number; itemIndex: number }>([], {
|
|
50
|
+
* comparator: (a, b) => a.value - b.value // Min heap
|
|
51
|
+
* });
|
|
52
|
+
*
|
|
53
|
+
* // Initialize heap
|
|
54
|
+
* sequences.forEach((seq, seqIndex) => {
|
|
55
|
+
* if (seq.length) {
|
|
56
|
+
* heap.add({ value: seq[0], seqIndex, itemIndex: 0 });
|
|
57
|
+
* }
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* const merged: number[] = [];
|
|
61
|
+
* while (!heap.isEmpty()) {
|
|
62
|
+
* const { value, seqIndex, itemIndex } = heap.poll()!;
|
|
63
|
+
* merged.push(value);
|
|
64
|
+
*
|
|
65
|
+
* if (itemIndex + 1 < sequences[seqIndex].length) {
|
|
66
|
+
* heap.add({
|
|
67
|
+
* value: sequences[seqIndex][itemIndex + 1],
|
|
68
|
+
* seqIndex,
|
|
69
|
+
* itemIndex: itemIndex + 1
|
|
70
|
+
* });
|
|
71
|
+
* }
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* return merged;
|
|
75
|
+
* }
|
|
76
|
+
*
|
|
77
|
+
* const sequences = [
|
|
78
|
+
* [1, 4, 7],
|
|
79
|
+
* [2, 5, 8],
|
|
80
|
+
* [3, 6, 9]
|
|
81
|
+
* ];
|
|
82
|
+
* console.log(mergeSortedSequences(sequences)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
83
|
+
* @example
|
|
84
|
+
* // Use Heap to dynamically maintain the median
|
|
85
|
+
* class MedianFinder {
|
|
86
|
+
* private low: MaxHeap<number>; // Max heap, stores the smaller half
|
|
87
|
+
* private high: MinHeap<number>; // Min heap, stores the larger half
|
|
88
|
+
*
|
|
89
|
+
* constructor() {
|
|
90
|
+
* this.low = new MaxHeap<number>([]);
|
|
91
|
+
* this.high = new MinHeap<number>([]);
|
|
92
|
+
* }
|
|
93
|
+
*
|
|
94
|
+
* addNum(num: number): void {
|
|
95
|
+
* if (this.low.isEmpty() || num <= this.low.peek()!) this.low.add(num);
|
|
96
|
+
* else this.high.add(num);
|
|
97
|
+
*
|
|
98
|
+
* // Balance heaps
|
|
99
|
+
* if (this.low.size > this.high.size + 1) this.high.add(this.low.poll()!);
|
|
100
|
+
* else if (this.high.size > this.low.size) this.low.add(this.high.poll()!);
|
|
101
|
+
* }
|
|
102
|
+
*
|
|
103
|
+
* findMedian(): number {
|
|
104
|
+
* if (this.low.size === this.high.size) return (this.low.peek()! + this.high.peek()!) / 2;
|
|
105
|
+
* return this.low.peek()!;
|
|
106
|
+
* }
|
|
107
|
+
* }
|
|
108
|
+
*
|
|
109
|
+
* const medianFinder = new MedianFinder();
|
|
110
|
+
* medianFinder.addNum(10);
|
|
111
|
+
* console.log(medianFinder.findMedian()); // 10
|
|
112
|
+
* medianFinder.addNum(20);
|
|
113
|
+
* console.log(medianFinder.findMedian()); // 15
|
|
114
|
+
* medianFinder.addNum(30);
|
|
115
|
+
* console.log(medianFinder.findMedian()); // 20
|
|
116
|
+
* medianFinder.addNum(40);
|
|
117
|
+
* console.log(medianFinder.findMedian()); // 25
|
|
118
|
+
* medianFinder.addNum(50);
|
|
119
|
+
* console.log(medianFinder.findMedian()); // 30
|
|
120
|
+
* @example
|
|
121
|
+
* // Use Heap for load balancing
|
|
122
|
+
* function loadBalance(requests: number[], servers: number): number[] {
|
|
123
|
+
* const serverHeap = new Heap<{ id: number; load: number }>([], { comparator: (a, b) => a.load - b.load }); // min heap
|
|
124
|
+
* const serverLoads = new Array(servers).fill(0);
|
|
125
|
+
*
|
|
126
|
+
* for (let i = 0; i < servers; i++) {
|
|
127
|
+
* serverHeap.add({ id: i, load: 0 });
|
|
128
|
+
* }
|
|
129
|
+
*
|
|
130
|
+
* requests.forEach(req => {
|
|
131
|
+
* const server = serverHeap.poll()!;
|
|
132
|
+
* serverLoads[server.id] += req;
|
|
133
|
+
* server.load += req;
|
|
134
|
+
* serverHeap.add(server); // The server after updating the load is re-entered into the heap
|
|
135
|
+
* });
|
|
136
|
+
*
|
|
137
|
+
* return serverLoads;
|
|
138
|
+
* }
|
|
139
|
+
*
|
|
140
|
+
* const requests = [5, 2, 8, 3, 7];
|
|
141
|
+
* console.log(loadBalance(requests, 3)); // [12, 8, 5]
|
|
142
|
+
* @example
|
|
143
|
+
* // Use Heap to schedule tasks
|
|
144
|
+
* type Task = [string, number];
|
|
145
|
+
*
|
|
146
|
+
* function scheduleTasks(tasks: Task[], machines: number): Map<number, Task[]> {
|
|
147
|
+
* const machineHeap = new Heap<{ id: number; load: number }>([], { comparator: (a, b) => a.load - b.load }); // Min heap
|
|
148
|
+
* const allocation = new Map<number, Task[]>();
|
|
149
|
+
*
|
|
150
|
+
* // Initialize the load on each machine
|
|
151
|
+
* for (let i = 0; i < machines; i++) {
|
|
152
|
+
* machineHeap.add({ id: i, load: 0 });
|
|
153
|
+
* allocation.set(i, []);
|
|
154
|
+
* }
|
|
155
|
+
*
|
|
156
|
+
* // Assign tasks
|
|
157
|
+
* tasks.forEach(([task, load]) => {
|
|
158
|
+
* const machine = machineHeap.poll()!;
|
|
159
|
+
* allocation.get(machine.id)!.push([task, load]);
|
|
160
|
+
* machine.load += load;
|
|
161
|
+
* machineHeap.add(machine); // The machine after updating the load is re-entered into the heap
|
|
162
|
+
* });
|
|
163
|
+
*
|
|
164
|
+
* return allocation;
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* const tasks: Task[] = [
|
|
168
|
+
* ['Task1', 3],
|
|
169
|
+
* ['Task2', 1],
|
|
170
|
+
* ['Task3', 2],
|
|
171
|
+
* ['Task4', 5],
|
|
172
|
+
* ['Task5', 4]
|
|
173
|
+
* ];
|
|
174
|
+
* const expectedMap = new Map<number, Task[]>();
|
|
175
|
+
* expectedMap.set(0, [
|
|
176
|
+
* ['Task1', 3],
|
|
177
|
+
* ['Task4', 5]
|
|
178
|
+
* ]);
|
|
179
|
+
* expectedMap.set(1, [
|
|
180
|
+
* ['Task2', 1],
|
|
181
|
+
* ['Task3', 2],
|
|
182
|
+
* ['Task5', 4]
|
|
183
|
+
* ]);
|
|
184
|
+
* console.log(scheduleTasks(tasks, 2)); // expectedMap
|
|
20
185
|
*/
|
|
21
186
|
export declare class Heap<E = any, R = any> extends IterableElementBase<E, R, Heap<E, R>> {
|
|
22
187
|
/**
|
|
@@ -19,6 +19,171 @@ const base_1 = require("../base");
|
|
|
19
19
|
* 6. Non-linear Search: While a heap allows rapid access to its largest or smallest element, it is less efficient for other operations, such as searching for a specific element, as it is not designed for these tasks.
|
|
20
20
|
* 7. Efficient Sorting Algorithms: For example, heap sort. Heap sort uses the properties of a heap to sort elements.
|
|
21
21
|
* 8. Graph Algorithms: Such as Dijkstra's shortest path algorithm and Prime's minimum-spanning tree algorithm, which use heaps to improve performance.
|
|
22
|
+
* @example
|
|
23
|
+
* // Use Heap to sort an array
|
|
24
|
+
* function heapSort(arr: number[]): number[] {
|
|
25
|
+
* const heap = new Heap<number>(arr, { comparator: (a, b) => a - b });
|
|
26
|
+
* const sorted: number[] = [];
|
|
27
|
+
* while (!heap.isEmpty()) {
|
|
28
|
+
* sorted.push(heap.poll()!); // Poll minimum element
|
|
29
|
+
* }
|
|
30
|
+
* return sorted;
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* const array = [5, 3, 8, 4, 1, 2];
|
|
34
|
+
* console.log(heapSort(array)); // [1, 2, 3, 4, 5, 8]
|
|
35
|
+
* @example
|
|
36
|
+
* // Use Heap to solve top k problems
|
|
37
|
+
* function topKElements(arr: number[], k: number): number[] {
|
|
38
|
+
* const heap = new Heap<number>([], { comparator: (a, b) => b - a }); // Max heap
|
|
39
|
+
* arr.forEach(num => {
|
|
40
|
+
* heap.add(num);
|
|
41
|
+
* if (heap.size > k) heap.poll(); // Keep the heap size at K
|
|
42
|
+
* });
|
|
43
|
+
* return heap.toArray();
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* const numbers = [10, 30, 20, 5, 15, 25];
|
|
47
|
+
* console.log(topKElements(numbers, 3)); // [15, 10, 5]
|
|
48
|
+
* @example
|
|
49
|
+
* // Use Heap to merge sorted sequences
|
|
50
|
+
* function mergeSortedSequences(sequences: number[][]): number[] {
|
|
51
|
+
* const heap = new Heap<{ value: number; seqIndex: number; itemIndex: number }>([], {
|
|
52
|
+
* comparator: (a, b) => a.value - b.value // Min heap
|
|
53
|
+
* });
|
|
54
|
+
*
|
|
55
|
+
* // Initialize heap
|
|
56
|
+
* sequences.forEach((seq, seqIndex) => {
|
|
57
|
+
* if (seq.length) {
|
|
58
|
+
* heap.add({ value: seq[0], seqIndex, itemIndex: 0 });
|
|
59
|
+
* }
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* const merged: number[] = [];
|
|
63
|
+
* while (!heap.isEmpty()) {
|
|
64
|
+
* const { value, seqIndex, itemIndex } = heap.poll()!;
|
|
65
|
+
* merged.push(value);
|
|
66
|
+
*
|
|
67
|
+
* if (itemIndex + 1 < sequences[seqIndex].length) {
|
|
68
|
+
* heap.add({
|
|
69
|
+
* value: sequences[seqIndex][itemIndex + 1],
|
|
70
|
+
* seqIndex,
|
|
71
|
+
* itemIndex: itemIndex + 1
|
|
72
|
+
* });
|
|
73
|
+
* }
|
|
74
|
+
* }
|
|
75
|
+
*
|
|
76
|
+
* return merged;
|
|
77
|
+
* }
|
|
78
|
+
*
|
|
79
|
+
* const sequences = [
|
|
80
|
+
* [1, 4, 7],
|
|
81
|
+
* [2, 5, 8],
|
|
82
|
+
* [3, 6, 9]
|
|
83
|
+
* ];
|
|
84
|
+
* console.log(mergeSortedSequences(sequences)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
85
|
+
* @example
|
|
86
|
+
* // Use Heap to dynamically maintain the median
|
|
87
|
+
* class MedianFinder {
|
|
88
|
+
* private low: MaxHeap<number>; // Max heap, stores the smaller half
|
|
89
|
+
* private high: MinHeap<number>; // Min heap, stores the larger half
|
|
90
|
+
*
|
|
91
|
+
* constructor() {
|
|
92
|
+
* this.low = new MaxHeap<number>([]);
|
|
93
|
+
* this.high = new MinHeap<number>([]);
|
|
94
|
+
* }
|
|
95
|
+
*
|
|
96
|
+
* addNum(num: number): void {
|
|
97
|
+
* if (this.low.isEmpty() || num <= this.low.peek()!) this.low.add(num);
|
|
98
|
+
* else this.high.add(num);
|
|
99
|
+
*
|
|
100
|
+
* // Balance heaps
|
|
101
|
+
* if (this.low.size > this.high.size + 1) this.high.add(this.low.poll()!);
|
|
102
|
+
* else if (this.high.size > this.low.size) this.low.add(this.high.poll()!);
|
|
103
|
+
* }
|
|
104
|
+
*
|
|
105
|
+
* findMedian(): number {
|
|
106
|
+
* if (this.low.size === this.high.size) return (this.low.peek()! + this.high.peek()!) / 2;
|
|
107
|
+
* return this.low.peek()!;
|
|
108
|
+
* }
|
|
109
|
+
* }
|
|
110
|
+
*
|
|
111
|
+
* const medianFinder = new MedianFinder();
|
|
112
|
+
* medianFinder.addNum(10);
|
|
113
|
+
* console.log(medianFinder.findMedian()); // 10
|
|
114
|
+
* medianFinder.addNum(20);
|
|
115
|
+
* console.log(medianFinder.findMedian()); // 15
|
|
116
|
+
* medianFinder.addNum(30);
|
|
117
|
+
* console.log(medianFinder.findMedian()); // 20
|
|
118
|
+
* medianFinder.addNum(40);
|
|
119
|
+
* console.log(medianFinder.findMedian()); // 25
|
|
120
|
+
* medianFinder.addNum(50);
|
|
121
|
+
* console.log(medianFinder.findMedian()); // 30
|
|
122
|
+
* @example
|
|
123
|
+
* // Use Heap for load balancing
|
|
124
|
+
* function loadBalance(requests: number[], servers: number): number[] {
|
|
125
|
+
* const serverHeap = new Heap<{ id: number; load: number }>([], { comparator: (a, b) => a.load - b.load }); // min heap
|
|
126
|
+
* const serverLoads = new Array(servers).fill(0);
|
|
127
|
+
*
|
|
128
|
+
* for (let i = 0; i < servers; i++) {
|
|
129
|
+
* serverHeap.add({ id: i, load: 0 });
|
|
130
|
+
* }
|
|
131
|
+
*
|
|
132
|
+
* requests.forEach(req => {
|
|
133
|
+
* const server = serverHeap.poll()!;
|
|
134
|
+
* serverLoads[server.id] += req;
|
|
135
|
+
* server.load += req;
|
|
136
|
+
* serverHeap.add(server); // The server after updating the load is re-entered into the heap
|
|
137
|
+
* });
|
|
138
|
+
*
|
|
139
|
+
* return serverLoads;
|
|
140
|
+
* }
|
|
141
|
+
*
|
|
142
|
+
* const requests = [5, 2, 8, 3, 7];
|
|
143
|
+
* console.log(loadBalance(requests, 3)); // [12, 8, 5]
|
|
144
|
+
* @example
|
|
145
|
+
* // Use Heap to schedule tasks
|
|
146
|
+
* type Task = [string, number];
|
|
147
|
+
*
|
|
148
|
+
* function scheduleTasks(tasks: Task[], machines: number): Map<number, Task[]> {
|
|
149
|
+
* const machineHeap = new Heap<{ id: number; load: number }>([], { comparator: (a, b) => a.load - b.load }); // Min heap
|
|
150
|
+
* const allocation = new Map<number, Task[]>();
|
|
151
|
+
*
|
|
152
|
+
* // Initialize the load on each machine
|
|
153
|
+
* for (let i = 0; i < machines; i++) {
|
|
154
|
+
* machineHeap.add({ id: i, load: 0 });
|
|
155
|
+
* allocation.set(i, []);
|
|
156
|
+
* }
|
|
157
|
+
*
|
|
158
|
+
* // Assign tasks
|
|
159
|
+
* tasks.forEach(([task, load]) => {
|
|
160
|
+
* const machine = machineHeap.poll()!;
|
|
161
|
+
* allocation.get(machine.id)!.push([task, load]);
|
|
162
|
+
* machine.load += load;
|
|
163
|
+
* machineHeap.add(machine); // The machine after updating the load is re-entered into the heap
|
|
164
|
+
* });
|
|
165
|
+
*
|
|
166
|
+
* return allocation;
|
|
167
|
+
* }
|
|
168
|
+
*
|
|
169
|
+
* const tasks: Task[] = [
|
|
170
|
+
* ['Task1', 3],
|
|
171
|
+
* ['Task2', 1],
|
|
172
|
+
* ['Task3', 2],
|
|
173
|
+
* ['Task4', 5],
|
|
174
|
+
* ['Task5', 4]
|
|
175
|
+
* ];
|
|
176
|
+
* const expectedMap = new Map<number, Task[]>();
|
|
177
|
+
* expectedMap.set(0, [
|
|
178
|
+
* ['Task1', 3],
|
|
179
|
+
* ['Task4', 5]
|
|
180
|
+
* ]);
|
|
181
|
+
* expectedMap.set(1, [
|
|
182
|
+
* ['Task2', 1],
|
|
183
|
+
* ['Task3', 2],
|
|
184
|
+
* ['Task5', 4]
|
|
185
|
+
* ]);
|
|
186
|
+
* console.log(scheduleTasks(tasks, 2)); // expectedMap
|
|
22
187
|
*/
|
|
23
188
|
class Heap extends base_1.IterableElementBase {
|
|
24
189
|
/**
|