data-structure-typed 1.33.6 → 1.33.7
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/.github/workflows/ci.yml +1 -0
- package/CHANGELOG.md +1 -1
- package/README.md +17 -24
- package/coverage/coverage-final.json +64 -63
- package/coverage/coverage-summary.json +8 -7
- package/dist/data-structures/binary-tree/segment-tree.js +24 -6
- package/dist/data-structures/binary-tree/segment-tree.js.map +1 -1
- package/dist/data-structures/hash/hash-map.js +306 -0
- package/dist/data-structures/hash/hash-map.js.map +1 -0
- package/dist/data-structures/hash/hash-table.js +128 -38
- package/dist/data-structures/hash/hash-table.js.map +1 -1
- package/dist/data-structures/hash/index.js +1 -0
- package/dist/data-structures/hash/index.js.map +1 -1
- package/dist/data-structures/linked-list/skip-linked-list.js +122 -5
- package/dist/data-structures/linked-list/skip-linked-list.js.map +1 -1
- package/dist/types/data-structures/hash.js +3 -0
- package/dist/types/data-structures/hash.js.map +1 -0
- package/dist/types/data-structures/index.js +1 -0
- package/dist/types/data-structures/index.js.map +1 -1
- package/docs/index.html +22 -26
- package/docs/modules.html +10 -4
- package/lib/data-structures/binary-tree/segment-tree.d.ts +4 -4
- package/lib/data-structures/binary-tree/segment-tree.js +30 -14
- package/lib/data-structures/hash/hash-map.d.ts +56 -0
- package/lib/data-structures/hash/hash-map.js +167 -0
- package/lib/data-structures/hash/hash-table.d.ts +67 -23
- package/lib/data-structures/hash/hash-table.js +154 -52
- package/lib/data-structures/hash/index.d.ts +1 -0
- package/lib/data-structures/hash/index.js +1 -0
- package/lib/data-structures/linked-list/skip-linked-list.d.ts +60 -1
- package/lib/data-structures/linked-list/skip-linked-list.js +136 -1
- package/lib/types/data-structures/hash.d.ts +1 -0
- package/lib/types/data-structures/hash.js +1 -0
- package/lib/types/data-structures/index.d.ts +1 -0
- package/lib/types/data-structures/index.js +1 -0
- package/package.json +1 -1
- package/src/data-structures/binary-tree/segment-tree.ts +32 -14
- package/src/data-structures/hash/hash-map.ts +203 -0
- package/src/data-structures/hash/hash-table.ts +176 -56
- package/src/data-structures/hash/index.ts +1 -0
- package/src/data-structures/linked-list/skip-linked-list.ts +166 -1
- package/src/types/data-structures/hash.ts +1 -0
- package/src/types/data-structures/index.ts +1 -0
- package/test/unit/data-structures/binary-tree/segment-tree.test.ts +50 -0
- package/test/unit/data-structures/hash/hash-map.test.ts +104 -0
- package/test/unit/data-structures/hash/hash-table.test.ts +97 -10
- package/test/unit/data-structures/linked-list/skip-list.test.ts +55 -0
- package/umd/bundle.min.js +1 -1
- package/umd/bundle.min.js.map +1 -1
- package/tsconfig.prod.json +0 -25
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
6
|
* @license MIT License
|
|
7
7
|
*/
|
|
8
|
-
export class
|
|
8
|
+
export class HashTableNode {
|
|
9
9
|
constructor(key, val) {
|
|
10
10
|
this.key = key;
|
|
11
11
|
this.val = val;
|
|
@@ -13,94 +13,162 @@ export class HashNode {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
export class HashTable {
|
|
16
|
+
get hashFn() {
|
|
17
|
+
return this._hashFn;
|
|
18
|
+
}
|
|
19
|
+
set hashFn(value) {
|
|
20
|
+
this._hashFn = value;
|
|
21
|
+
}
|
|
16
22
|
get buckets() {
|
|
17
23
|
return this._buckets;
|
|
18
24
|
}
|
|
19
25
|
set buckets(value) {
|
|
20
26
|
this._buckets = value;
|
|
21
27
|
}
|
|
22
|
-
get size() {
|
|
23
|
-
return this._size;
|
|
24
|
-
}
|
|
25
|
-
set size(value) {
|
|
26
|
-
this._size = value;
|
|
27
|
-
}
|
|
28
28
|
get capacity() {
|
|
29
29
|
return this._capacity;
|
|
30
30
|
}
|
|
31
31
|
set capacity(value) {
|
|
32
32
|
this._capacity = value;
|
|
33
33
|
}
|
|
34
|
+
constructor(capacity = HashTable.DEFAULT_CAPACITY, hashFn) {
|
|
35
|
+
this._hashFn = hashFn || this._defaultHashFn;
|
|
36
|
+
this._capacity = Math.max(capacity, HashTable.DEFAULT_CAPACITY);
|
|
37
|
+
this._size = 0;
|
|
38
|
+
this._buckets = new Array(this._capacity).fill(null);
|
|
39
|
+
}
|
|
34
40
|
/**
|
|
35
|
-
* The
|
|
36
|
-
*
|
|
37
|
-
*
|
|
41
|
+
* The function `_defaultHashFn` calculates the hash value of a given key and returns the remainder when divided by the
|
|
42
|
+
* capacity of the data structure.
|
|
43
|
+
* @param {K} key - The `key` parameter is the input value that needs to be hashed. It can be of any type, but in this
|
|
44
|
+
* code snippet, it is checked whether the key is a string or an object. If it is a string, the `_murmurStringHashFn`
|
|
45
|
+
* function is used to
|
|
46
|
+
* @returns the hash value of the key modulo the capacity of the data structure.
|
|
38
47
|
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
|
|
48
|
+
_defaultHashFn(key) {
|
|
49
|
+
// Can be replaced with other hash functions as needed
|
|
50
|
+
const hashValue = typeof key === 'string' ? this._murmurStringHashFn(key) : this._objectHash(key);
|
|
51
|
+
return hashValue % this._capacity;
|
|
43
52
|
}
|
|
44
53
|
/**
|
|
45
|
-
* The
|
|
46
|
-
*
|
|
47
|
-
* @param {K} key - The `key` parameter
|
|
48
|
-
*
|
|
49
|
-
* @returns
|
|
54
|
+
* The `_multiplicativeStringHashFn` function calculates a hash value for a given string key using the multiplicative
|
|
55
|
+
* string hash function.
|
|
56
|
+
* @param {K} key - The `key` parameter is the input value for which we want to calculate the hash. It can be of any
|
|
57
|
+
* type, as it is generic (`K`). The function converts the `key` to a string using the `String()` function.
|
|
58
|
+
* @returns a number, which is the result of the multiplicative string hash function applied to the input key.
|
|
50
59
|
*/
|
|
51
|
-
|
|
60
|
+
_multiplicativeStringHashFn(key) {
|
|
52
61
|
const keyString = String(key);
|
|
53
62
|
let hash = 0;
|
|
54
63
|
for (let i = 0; i < keyString.length; i++) {
|
|
55
|
-
|
|
64
|
+
const charCode = keyString.charCodeAt(i);
|
|
65
|
+
// Some constants for adjusting the hash function
|
|
66
|
+
const A = 0.618033988749895;
|
|
67
|
+
const M = 1 << 30; // 2^30
|
|
68
|
+
hash = (hash * A + charCode) % M;
|
|
69
|
+
}
|
|
70
|
+
return Math.abs(hash); // Take absolute value to ensure non-negative numbers
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The function `_murmurStringHashFn` calculates a hash value for a given string key using the MurmurHash algorithm.
|
|
74
|
+
* @param {K} key - The `key` parameter is the input value for which you want to calculate the hash. It can be of any
|
|
75
|
+
* type, but it will be converted to a string using the `String()` function before calculating the hash.
|
|
76
|
+
* @returns a number, which is the hash value calculated for the given key.
|
|
77
|
+
*/
|
|
78
|
+
_murmurStringHashFn(key) {
|
|
79
|
+
const keyString = String(key);
|
|
80
|
+
const seed = 0;
|
|
81
|
+
let hash = seed;
|
|
82
|
+
for (let i = 0; i < keyString.length; i++) {
|
|
83
|
+
const char = keyString.charCodeAt(i);
|
|
84
|
+
hash = (hash ^ char) * 0x5bd1e995;
|
|
85
|
+
hash = (hash ^ (hash >>> 15)) * 0x27d4eb2d;
|
|
86
|
+
hash = hash ^ (hash >>> 15);
|
|
87
|
+
}
|
|
88
|
+
return Math.abs(hash);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* The _hash function takes a key and returns a number.
|
|
92
|
+
* @param {K} key - The parameter "key" is of type K, which represents the type of the key that will be hashed.
|
|
93
|
+
* @returns The hash function is returning a number.
|
|
94
|
+
*/
|
|
95
|
+
_hash(key) {
|
|
96
|
+
return this.hashFn(key);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The function calculates a hash value for a given string using the djb2 algorithm.
|
|
100
|
+
* @param {string} key - The `key` parameter in the `stringHash` function is a string value that represents the input for
|
|
101
|
+
* which we want to calculate the hash value.
|
|
102
|
+
* @returns a number, which is the hash value of the input string.
|
|
103
|
+
*/
|
|
104
|
+
_stringHash(key) {
|
|
105
|
+
let hash = 0;
|
|
106
|
+
for (let i = 0; i < key.length; i++) {
|
|
107
|
+
hash = (hash * 31 + key.charCodeAt(i)) & 0xffffffff;
|
|
56
108
|
}
|
|
57
|
-
return hash
|
|
109
|
+
return hash;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The function `_objectHash` takes a key and returns a hash value, using a custom hash function for objects.
|
|
113
|
+
* @param {K} key - The parameter "key" is of type "K", which means it can be any type. It could be a string, number,
|
|
114
|
+
* boolean, object, or any other type of value. The purpose of the objectHash function is to generate a hash value for
|
|
115
|
+
* the key, which can be used for
|
|
116
|
+
* @returns a number, which is the hash value of the key.
|
|
117
|
+
*/
|
|
118
|
+
_objectHash(key) {
|
|
119
|
+
// If the key is an object, you can write a custom hash function
|
|
120
|
+
// For example, convert the object's properties to a string and use string hashing
|
|
121
|
+
// This is just an example; you should write a specific object hash function as needed
|
|
122
|
+
return this._stringHash(JSON.stringify(key));
|
|
58
123
|
}
|
|
59
124
|
/**
|
|
60
|
-
* The
|
|
125
|
+
* The set function adds a key-value pair to the hash table, handling collisions and resizing if necessary.
|
|
61
126
|
* @param {K} key - The key parameter represents the key of the key-value pair that you want to insert into the hash
|
|
62
|
-
* table. It is of type K, which
|
|
63
|
-
* @param {V} val - The `val`
|
|
64
|
-
*
|
|
127
|
+
* table. It is of type K, which is a generic type representing the key's data type.
|
|
128
|
+
* @param {V} val - The parameter `val` represents the value that you want to associate with the given key in the hash
|
|
129
|
+
* table.
|
|
130
|
+
* @returns Nothing is being returned. The return type of the `put` method is `void`, which means it does not return any
|
|
131
|
+
* value.
|
|
65
132
|
*/
|
|
66
|
-
|
|
67
|
-
const index = this.
|
|
68
|
-
const newNode = new
|
|
69
|
-
if (!this.
|
|
70
|
-
this.
|
|
133
|
+
set(key, val) {
|
|
134
|
+
const index = this._hash(key);
|
|
135
|
+
const newNode = new HashTableNode(key, val);
|
|
136
|
+
if (!this._buckets[index]) {
|
|
137
|
+
this._buckets[index] = newNode;
|
|
71
138
|
}
|
|
72
139
|
else {
|
|
73
|
-
// Handle
|
|
74
|
-
let currentNode = this.
|
|
75
|
-
while (currentNode
|
|
140
|
+
// Handle collisions, consider using open addressing, etc.
|
|
141
|
+
let currentNode = this._buckets[index];
|
|
142
|
+
while (currentNode) {
|
|
76
143
|
if (currentNode.key === key) {
|
|
77
|
-
//
|
|
144
|
+
// If the key already exists, update the value
|
|
78
145
|
currentNode.val = val;
|
|
79
146
|
return;
|
|
80
147
|
}
|
|
148
|
+
if (!currentNode.next) {
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
81
151
|
currentNode = currentNode.next;
|
|
82
152
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
153
|
+
// Add to the end of the linked list
|
|
154
|
+
currentNode.next = newNode;
|
|
155
|
+
}
|
|
156
|
+
this._size++;
|
|
157
|
+
// If the load factor is too high, resize the hash table
|
|
158
|
+
if (this._size / this._capacity >= HashTable.LOAD_FACTOR) {
|
|
159
|
+
this._expand();
|
|
91
160
|
}
|
|
92
|
-
this.size++;
|
|
93
161
|
}
|
|
94
162
|
/**
|
|
95
163
|
* The `get` function retrieves the value associated with a given key from a hash table.
|
|
96
|
-
* @param {K} key - The parameter
|
|
164
|
+
* @param {K} key - The `key` parameter represents the key of the element that we want to retrieve from the data
|
|
97
165
|
* structure.
|
|
98
166
|
* @returns The method is returning the value associated with the given key if it exists in the hash table. If the key is
|
|
99
167
|
* not found, it returns `undefined`.
|
|
100
168
|
*/
|
|
101
169
|
get(key) {
|
|
102
|
-
const index = this.
|
|
103
|
-
let currentNode = this.
|
|
170
|
+
const index = this._hash(key);
|
|
171
|
+
let currentNode = this._buckets[index];
|
|
104
172
|
while (currentNode) {
|
|
105
173
|
if (currentNode.key === key) {
|
|
106
174
|
return currentNode.val;
|
|
@@ -110,15 +178,15 @@ export class HashTable {
|
|
|
110
178
|
return undefined; // Key not found
|
|
111
179
|
}
|
|
112
180
|
/**
|
|
113
|
-
* The
|
|
181
|
+
* The remove function removes a key-value pair from a hash table.
|
|
114
182
|
* @param {K} key - The `key` parameter represents the key of the key-value pair that needs to be removed from the hash
|
|
115
183
|
* table.
|
|
116
184
|
* @returns Nothing is being returned. The `remove` method has a return type of `void`, which means it does not return
|
|
117
185
|
* any value.
|
|
118
186
|
*/
|
|
119
187
|
remove(key) {
|
|
120
|
-
const index = this.
|
|
121
|
-
let currentNode = this.
|
|
188
|
+
const index = this._hash(key);
|
|
189
|
+
let currentNode = this._buckets[index];
|
|
122
190
|
let prevNode = null;
|
|
123
191
|
while (currentNode) {
|
|
124
192
|
if (currentNode.key === key) {
|
|
@@ -126,13 +194,47 @@ export class HashTable {
|
|
|
126
194
|
prevNode.next = currentNode.next;
|
|
127
195
|
}
|
|
128
196
|
else {
|
|
129
|
-
this.
|
|
197
|
+
this._buckets[index] = currentNode.next;
|
|
130
198
|
}
|
|
131
|
-
this.
|
|
199
|
+
this._size--;
|
|
200
|
+
currentNode.next = null; // Release memory
|
|
132
201
|
return;
|
|
133
202
|
}
|
|
134
203
|
prevNode = currentNode;
|
|
135
204
|
currentNode = currentNode.next;
|
|
136
205
|
}
|
|
137
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* The `expand` function increases the capacity of a hash table by creating a new array of buckets with double the
|
|
209
|
+
* capacity and rehashing all the existing key-value pairs into the new buckets.
|
|
210
|
+
*/
|
|
211
|
+
_expand() {
|
|
212
|
+
const newCapacity = this._capacity * 2;
|
|
213
|
+
const newBuckets = new Array(newCapacity).fill(null);
|
|
214
|
+
for (const bucket of this._buckets) {
|
|
215
|
+
let currentNode = bucket;
|
|
216
|
+
while (currentNode) {
|
|
217
|
+
const newIndex = this._hash(currentNode.key);
|
|
218
|
+
const newNode = new HashTableNode(currentNode.key, currentNode.val);
|
|
219
|
+
if (!newBuckets[newIndex]) {
|
|
220
|
+
newBuckets[newIndex] = newNode;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
let currentNewNode = newBuckets[newIndex];
|
|
224
|
+
while (currentNewNode.next) {
|
|
225
|
+
currentNewNode = currentNewNode.next;
|
|
226
|
+
}
|
|
227
|
+
currentNewNode.next = newNode;
|
|
228
|
+
}
|
|
229
|
+
currentNode = currentNode.next;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
this._buckets = newBuckets;
|
|
233
|
+
this._capacity = newCapacity;
|
|
234
|
+
}
|
|
235
|
+
get size() {
|
|
236
|
+
return this._size;
|
|
237
|
+
}
|
|
138
238
|
}
|
|
239
|
+
HashTable.DEFAULT_CAPACITY = 16;
|
|
240
|
+
HashTable.LOAD_FACTOR = 0.75;
|
|
@@ -1,2 +1,61 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* data-structure-typed
|
|
3
|
+
*
|
|
4
|
+
* @author Tyler Zeng
|
|
5
|
+
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
|
+
* @license MIT License
|
|
7
|
+
*/
|
|
8
|
+
export declare class SkipListNode<K, V> {
|
|
9
|
+
key: K;
|
|
10
|
+
value: V;
|
|
11
|
+
forward: SkipListNode<K, V>[];
|
|
12
|
+
constructor(key: K, value: V, level: number);
|
|
13
|
+
}
|
|
14
|
+
export declare class SkipList<K, V> {
|
|
15
|
+
get probability(): number;
|
|
16
|
+
set probability(value: number);
|
|
17
|
+
get maxLevel(): number;
|
|
18
|
+
set maxLevel(value: number);
|
|
19
|
+
get level(): number;
|
|
20
|
+
set level(value: number);
|
|
21
|
+
get head(): SkipListNode<K, V>;
|
|
22
|
+
set head(value: SkipListNode<K, V>);
|
|
23
|
+
private _head;
|
|
24
|
+
private _level;
|
|
25
|
+
private _maxLevel;
|
|
26
|
+
private _probability;
|
|
27
|
+
/**
|
|
28
|
+
* The constructor initializes a SkipList with a specified maximum level and probability.
|
|
29
|
+
* @param [maxLevel=16] - The `maxLevel` parameter represents the maximum level that a skip list can have. It determines
|
|
30
|
+
* the maximum number of levels that can be created in the skip list.
|
|
31
|
+
* @param [probability=0.5] - The probability parameter represents the probability of a node being promoted to a higher
|
|
32
|
+
* level in the skip list. It is used to determine the height of each node in the skip list.
|
|
33
|
+
*/
|
|
34
|
+
constructor(maxLevel?: number, probability?: number);
|
|
35
|
+
/**
|
|
36
|
+
* The function "randomLevel" generates a random level based on a given probability and maximum level.
|
|
37
|
+
* @returns the level, which is a number.
|
|
38
|
+
*/
|
|
39
|
+
private randomLevel;
|
|
40
|
+
/**
|
|
41
|
+
* The add function adds a new node with a given key and value to a Skip List data structure.
|
|
42
|
+
* @param {K} key - The key parameter represents the key of the node that needs to be added to the skip list.
|
|
43
|
+
* @param {V} value - The "value" parameter represents the value associated with the key that is being added to the Skip
|
|
44
|
+
* List.
|
|
45
|
+
*/
|
|
46
|
+
add(key: K, value: V): void;
|
|
47
|
+
/**
|
|
48
|
+
* The function `get` retrieves the value associated with a given key from a skip list data structure.
|
|
49
|
+
* @param {K} key - The `key` parameter is the key of the element that we want to retrieve from the data structure.
|
|
50
|
+
* @returns The method `get(key: K)` returns the value associated with the given key if it exists in the data structure,
|
|
51
|
+
* otherwise it returns `undefined`.
|
|
52
|
+
*/
|
|
53
|
+
get(key: K): V | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* The `remove` function removes a node with a specific key from a Skip List data structure.
|
|
56
|
+
* @param {K} key - The key parameter represents the key of the node that needs to be removed from the skip list.
|
|
57
|
+
* @returns The `remove` method returns a boolean value. It returns `true` if the key was successfully removed from the
|
|
58
|
+
* skip list, and `false` if the key was not found in the skip list.
|
|
59
|
+
*/
|
|
60
|
+
remove(key: K): boolean;
|
|
2
61
|
}
|
|
@@ -1,2 +1,137 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* data-structure-typed
|
|
3
|
+
*
|
|
4
|
+
* @author Tyler Zeng
|
|
5
|
+
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
|
6
|
+
* @license MIT License
|
|
7
|
+
*/
|
|
8
|
+
export class SkipListNode {
|
|
9
|
+
constructor(key, value, level) {
|
|
10
|
+
this.key = key;
|
|
11
|
+
this.value = value;
|
|
12
|
+
this.forward = new Array(level);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class SkipList {
|
|
16
|
+
get probability() {
|
|
17
|
+
return this._probability;
|
|
18
|
+
}
|
|
19
|
+
set probability(value) {
|
|
20
|
+
this._probability = value;
|
|
21
|
+
}
|
|
22
|
+
get maxLevel() {
|
|
23
|
+
return this._maxLevel;
|
|
24
|
+
}
|
|
25
|
+
set maxLevel(value) {
|
|
26
|
+
this._maxLevel = value;
|
|
27
|
+
}
|
|
28
|
+
get level() {
|
|
29
|
+
return this._level;
|
|
30
|
+
}
|
|
31
|
+
set level(value) {
|
|
32
|
+
this._level = value;
|
|
33
|
+
}
|
|
34
|
+
get head() {
|
|
35
|
+
return this._head;
|
|
36
|
+
}
|
|
37
|
+
set head(value) {
|
|
38
|
+
this._head = value;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The constructor initializes a SkipList with a specified maximum level and probability.
|
|
42
|
+
* @param [maxLevel=16] - The `maxLevel` parameter represents the maximum level that a skip list can have. It determines
|
|
43
|
+
* the maximum number of levels that can be created in the skip list.
|
|
44
|
+
* @param [probability=0.5] - The probability parameter represents the probability of a node being promoted to a higher
|
|
45
|
+
* level in the skip list. It is used to determine the height of each node in the skip list.
|
|
46
|
+
*/
|
|
47
|
+
constructor(maxLevel = 16, probability = 0.5) {
|
|
48
|
+
this._head = new SkipListNode(null, null, maxLevel);
|
|
49
|
+
this._level = 0;
|
|
50
|
+
this._maxLevel = maxLevel;
|
|
51
|
+
this._probability = probability;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The function "randomLevel" generates a random level based on a given probability and maximum level.
|
|
55
|
+
* @returns the level, which is a number.
|
|
56
|
+
*/
|
|
57
|
+
randomLevel() {
|
|
58
|
+
let level = 1;
|
|
59
|
+
while (Math.random() < this.probability && level < this.maxLevel) {
|
|
60
|
+
level++;
|
|
61
|
+
}
|
|
62
|
+
return level;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The add function adds a new node with a given key and value to a Skip List data structure.
|
|
66
|
+
* @param {K} key - The key parameter represents the key of the node that needs to be added to the skip list.
|
|
67
|
+
* @param {V} value - The "value" parameter represents the value associated with the key that is being added to the Skip
|
|
68
|
+
* List.
|
|
69
|
+
*/
|
|
70
|
+
add(key, value) {
|
|
71
|
+
const newNode = new SkipListNode(key, value, this.randomLevel());
|
|
72
|
+
const update = new Array(this.maxLevel).fill(this.head);
|
|
73
|
+
let current = this.head;
|
|
74
|
+
for (let i = this.level - 1; i >= 0; i--) {
|
|
75
|
+
while (current.forward[i] && current.forward[i].key < key) {
|
|
76
|
+
current = current.forward[i];
|
|
77
|
+
}
|
|
78
|
+
update[i] = current;
|
|
79
|
+
}
|
|
80
|
+
for (let i = 0; i < newNode.forward.length; i++) {
|
|
81
|
+
newNode.forward[i] = update[i].forward[i];
|
|
82
|
+
update[i].forward[i] = newNode;
|
|
83
|
+
}
|
|
84
|
+
if (newNode.forward[0] !== null) {
|
|
85
|
+
this.level = Math.max(this.level, newNode.forward.length);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The function `get` retrieves the value associated with a given key from a skip list data structure.
|
|
90
|
+
* @param {K} key - The `key` parameter is the key of the element that we want to retrieve from the data structure.
|
|
91
|
+
* @returns The method `get(key: K)` returns the value associated with the given key if it exists in the data structure,
|
|
92
|
+
* otherwise it returns `undefined`.
|
|
93
|
+
*/
|
|
94
|
+
get(key) {
|
|
95
|
+
let current = this.head;
|
|
96
|
+
for (let i = this.level - 1; i >= 0; i--) {
|
|
97
|
+
while (current.forward[i] && current.forward[i].key < key) {
|
|
98
|
+
current = current.forward[i];
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
current = current.forward[0];
|
|
102
|
+
if (current && current.key === key) {
|
|
103
|
+
return current.value;
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* The `remove` function removes a node with a specific key from a Skip List data structure.
|
|
109
|
+
* @param {K} key - The key parameter represents the key of the node that needs to be removed from the skip list.
|
|
110
|
+
* @returns The `remove` method returns a boolean value. It returns `true` if the key was successfully removed from the
|
|
111
|
+
* skip list, and `false` if the key was not found in the skip list.
|
|
112
|
+
*/
|
|
113
|
+
remove(key) {
|
|
114
|
+
const update = new Array(this.maxLevel).fill(this.head);
|
|
115
|
+
let current = this.head;
|
|
116
|
+
for (let i = this.level - 1; i >= 0; i--) {
|
|
117
|
+
while (current.forward[i] && current.forward[i].key < key) {
|
|
118
|
+
current = current.forward[i];
|
|
119
|
+
}
|
|
120
|
+
update[i] = current;
|
|
121
|
+
}
|
|
122
|
+
current = current.forward[0];
|
|
123
|
+
if (current && current.key === key) {
|
|
124
|
+
for (let i = 0; i < this.level; i++) {
|
|
125
|
+
if (update[i].forward[i] !== current) {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
update[i].forward[i] = current.forward[i];
|
|
129
|
+
}
|
|
130
|
+
while (this.level > 0 && this.head.forward[this.level - 1] === null) {
|
|
131
|
+
this.level--;
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
2
137
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type HashFunction<K> = (key: K) => number;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "data-structure-typed",
|
|
3
|
-
"version": "1.33.
|
|
3
|
+
"version": "1.33.7",
|
|
4
4
|
"description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "lib/index.js",
|
|
@@ -87,12 +87,21 @@ export class SegmentTree {
|
|
|
87
87
|
* included in the range. If not provided, it defaults to the index of the last element in the "values" array.
|
|
88
88
|
*/
|
|
89
89
|
constructor(values: number[], start?: number, end?: number) {
|
|
90
|
+
console.log('values.length:', values.length);
|
|
90
91
|
start = start || 0;
|
|
91
92
|
end = end || values.length - 1;
|
|
92
93
|
this._values = values;
|
|
93
94
|
this._start = start;
|
|
94
95
|
this._end = end;
|
|
95
|
-
|
|
96
|
+
|
|
97
|
+
if (values.length > 0) {
|
|
98
|
+
console.log('Initializing with non-empty array');
|
|
99
|
+
this._root = this.build(start, end);
|
|
100
|
+
} else {
|
|
101
|
+
console.log('Initializing with empty array');
|
|
102
|
+
this._root = null;
|
|
103
|
+
this._values = [];
|
|
104
|
+
}
|
|
96
105
|
}
|
|
97
106
|
|
|
98
107
|
private _values: number[] = [];
|
|
@@ -119,15 +128,18 @@ export class SegmentTree {
|
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
/**
|
|
122
|
-
* The function
|
|
123
|
-
*
|
|
131
|
+
* The build function creates a segment tree by recursively dividing the given range into smaller segments and assigning
|
|
132
|
+
* the sum of values to each segment.
|
|
124
133
|
* @param {number} start - The `start` parameter represents the starting index of the segment or range for which we are
|
|
125
134
|
* building the segment tree.
|
|
126
|
-
* @param {number} end - The
|
|
127
|
-
*
|
|
135
|
+
* @param {number} end - The "end" parameter represents the ending index of the segment or range for which we want to
|
|
136
|
+
* build a segment tree.
|
|
128
137
|
* @returns a SegmentTreeNode object.
|
|
129
138
|
*/
|
|
130
139
|
build(start: number, end: number): SegmentTreeNode {
|
|
140
|
+
if (start > end) {
|
|
141
|
+
return new SegmentTreeNode(start, end, 0);
|
|
142
|
+
}
|
|
131
143
|
if (start === end) return new SegmentTreeNode(start, end, this._values[start]);
|
|
132
144
|
|
|
133
145
|
const mid = start + Math.floor((end - start) / 2);
|
|
@@ -192,33 +204,39 @@ export class SegmentTree {
|
|
|
192
204
|
return 0;
|
|
193
205
|
}
|
|
194
206
|
|
|
207
|
+
if (indexA < 0 || indexB >= this.values.length || indexA > indexB) {
|
|
208
|
+
return NaN;
|
|
209
|
+
}
|
|
210
|
+
|
|
195
211
|
const dfs = (cur: SegmentTreeNode, i: number, j: number): number => {
|
|
196
|
-
if (cur.start
|
|
212
|
+
if (i <= cur.start && j >= cur.end) {
|
|
213
|
+
// The range [i, j] completely covers the current node's range [cur.start, cur.end]
|
|
197
214
|
return cur.sum;
|
|
198
215
|
}
|
|
199
216
|
const mid = cur.start + Math.floor((cur.end - cur.start) / 2);
|
|
200
217
|
if (j <= mid) {
|
|
201
|
-
// TODO after no-non-null-assertion not ensure the logic
|
|
202
218
|
if (cur.left) {
|
|
203
219
|
return dfs(cur.left, i, j);
|
|
204
220
|
} else {
|
|
205
221
|
return NaN;
|
|
206
222
|
}
|
|
207
223
|
} else if (i > mid) {
|
|
208
|
-
// TODO after no-non-null-assertion not ensure the logic
|
|
209
224
|
if (cur.right) {
|
|
210
|
-
// TODO after no-non-null-assertion not ensure the logic
|
|
211
225
|
return dfs(cur.right, i, j);
|
|
212
226
|
} else {
|
|
213
227
|
return NaN;
|
|
214
228
|
}
|
|
215
229
|
} else {
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
230
|
+
// Query both left and right subtrees
|
|
231
|
+
let leftSum = 0;
|
|
232
|
+
let rightSum = 0;
|
|
233
|
+
if (cur.left) {
|
|
234
|
+
leftSum = dfs(cur.left, i, mid);
|
|
235
|
+
}
|
|
236
|
+
if (cur.right) {
|
|
237
|
+
rightSum = dfs(cur.right, mid + 1, j);
|
|
221
238
|
}
|
|
239
|
+
return leftSum + rightSum;
|
|
222
240
|
}
|
|
223
241
|
};
|
|
224
242
|
return dfs(root, indexA, indexB);
|