data-structure-typed 1.33.5 → 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 +18 -25
- package/coverage/coverage-final.json +64 -63
- package/coverage/coverage-summary.json +7 -6
- 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 +23 -27
- 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/doubly-linked-list.test.ts +1 -1
- 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
|
@@ -1 +1,166 @@
|
|
|
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
|
+
|
|
9
|
+
export class SkipListNode<K, V> {
|
|
10
|
+
key: K;
|
|
11
|
+
value: V;
|
|
12
|
+
forward: SkipListNode<K, V>[];
|
|
13
|
+
|
|
14
|
+
constructor(key: K, value: V, level: number) {
|
|
15
|
+
this.key = key;
|
|
16
|
+
this.value = value;
|
|
17
|
+
this.forward = new Array(level);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class SkipList<K, V> {
|
|
22
|
+
get probability(): number {
|
|
23
|
+
return this._probability;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
set probability(value: number) {
|
|
27
|
+
this._probability = value;
|
|
28
|
+
}
|
|
29
|
+
get maxLevel(): number {
|
|
30
|
+
return this._maxLevel;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
set maxLevel(value: number) {
|
|
34
|
+
this._maxLevel = value;
|
|
35
|
+
}
|
|
36
|
+
get level(): number {
|
|
37
|
+
return this._level;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
set level(value: number) {
|
|
41
|
+
this._level = value;
|
|
42
|
+
}
|
|
43
|
+
get head(): SkipListNode<K, V> {
|
|
44
|
+
return this._head;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
set head(value: SkipListNode<K, V>) {
|
|
48
|
+
this._head = value;
|
|
49
|
+
}
|
|
50
|
+
private _head: SkipListNode<K, V>;
|
|
51
|
+
private _level: number;
|
|
52
|
+
private _maxLevel: number;
|
|
53
|
+
private _probability: number;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The constructor initializes a SkipList with a specified maximum level and probability.
|
|
57
|
+
* @param [maxLevel=16] - The `maxLevel` parameter represents the maximum level that a skip list can have. It determines
|
|
58
|
+
* the maximum number of levels that can be created in the skip list.
|
|
59
|
+
* @param [probability=0.5] - The probability parameter represents the probability of a node being promoted to a higher
|
|
60
|
+
* level in the skip list. It is used to determine the height of each node in the skip list.
|
|
61
|
+
*/
|
|
62
|
+
constructor(maxLevel = 16, probability = 0.5) {
|
|
63
|
+
this._head = new SkipListNode<K, V>(null as any, null as any, maxLevel);
|
|
64
|
+
this._level = 0;
|
|
65
|
+
this._maxLevel = maxLevel;
|
|
66
|
+
this._probability = probability;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The function "randomLevel" generates a random level based on a given probability and maximum level.
|
|
71
|
+
* @returns the level, which is a number.
|
|
72
|
+
*/
|
|
73
|
+
private randomLevel(): number {
|
|
74
|
+
let level = 1;
|
|
75
|
+
while (Math.random() < this.probability && level < this.maxLevel) {
|
|
76
|
+
level++;
|
|
77
|
+
}
|
|
78
|
+
return level;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The add function adds a new node with a given key and value to a Skip List data structure.
|
|
83
|
+
* @param {K} key - The key parameter represents the key of the node that needs to be added to the skip list.
|
|
84
|
+
* @param {V} value - The "value" parameter represents the value associated with the key that is being added to the Skip
|
|
85
|
+
* List.
|
|
86
|
+
*/
|
|
87
|
+
add(key: K, value: V): void {
|
|
88
|
+
const newNode = new SkipListNode(key, value, this.randomLevel());
|
|
89
|
+
const update: SkipListNode<K, V>[] = new Array(this.maxLevel).fill(this.head);
|
|
90
|
+
let current = this.head;
|
|
91
|
+
|
|
92
|
+
for (let i = this.level - 1; i >= 0; i--) {
|
|
93
|
+
while (current.forward[i] && current.forward[i].key < key) {
|
|
94
|
+
current = current.forward[i];
|
|
95
|
+
}
|
|
96
|
+
update[i] = current;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (let i = 0; i < newNode.forward.length; i++) {
|
|
100
|
+
newNode.forward[i] = update[i].forward[i];
|
|
101
|
+
update[i].forward[i] = newNode;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (newNode.forward[0] !== null) {
|
|
105
|
+
this.level = Math.max(this.level, newNode.forward.length);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The function `get` retrieves the value associated with a given key from a skip list data structure.
|
|
111
|
+
* @param {K} key - The `key` parameter is the key of the element that we want to retrieve from the data structure.
|
|
112
|
+
* @returns The method `get(key: K)` returns the value associated with the given key if it exists in the data structure,
|
|
113
|
+
* otherwise it returns `undefined`.
|
|
114
|
+
*/
|
|
115
|
+
get(key: K): V | undefined {
|
|
116
|
+
let current = this.head;
|
|
117
|
+
for (let i = this.level - 1; i >= 0; i--) {
|
|
118
|
+
while (current.forward[i] && current.forward[i].key < key) {
|
|
119
|
+
current = current.forward[i];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
current = current.forward[0];
|
|
124
|
+
|
|
125
|
+
if (current && current.key === key) {
|
|
126
|
+
return current.value;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* The `remove` function removes a node with a specific key from a Skip List data structure.
|
|
134
|
+
* @param {K} key - The key parameter represents the key of the node that needs to be removed from the skip list.
|
|
135
|
+
* @returns The `remove` method returns a boolean value. It returns `true` if the key was successfully removed from the
|
|
136
|
+
* skip list, and `false` if the key was not found in the skip list.
|
|
137
|
+
*/
|
|
138
|
+
remove(key: K): boolean {
|
|
139
|
+
const update: SkipListNode<K, V>[] = new Array(this.maxLevel).fill(this.head);
|
|
140
|
+
let current = this.head;
|
|
141
|
+
|
|
142
|
+
for (let i = this.level - 1; i >= 0; i--) {
|
|
143
|
+
while (current.forward[i] && current.forward[i].key < key) {
|
|
144
|
+
current = current.forward[i];
|
|
145
|
+
}
|
|
146
|
+
update[i] = current;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
current = current.forward[0];
|
|
150
|
+
|
|
151
|
+
if (current && current.key === key) {
|
|
152
|
+
for (let i = 0; i < this.level; i++) {
|
|
153
|
+
if (update[i].forward[i] !== current) {
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
update[i].forward[i] = current.forward[i];
|
|
157
|
+
}
|
|
158
|
+
while (this.level > 0 && this.head.forward[this.level - 1] === null) {
|
|
159
|
+
this.level--;
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type HashFunction<K> = (key: K) => number;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {SegmentTree} from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('SegmentTree', () => {
|
|
4
|
+
let segmentTree: SegmentTree;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
// Create an example SegmentTree for testing
|
|
8
|
+
const values = [1, 2, 3, 4, 5];
|
|
9
|
+
segmentTree = new SegmentTree(values);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should build a valid segment tree', () => {
|
|
13
|
+
// Check if the root node's sum is correct
|
|
14
|
+
expect(segmentTree.root?.sum).toBe(15);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should update a node in the segment tree', () => {
|
|
18
|
+
// Update a node value
|
|
19
|
+
segmentTree.updateNode(2, 10);
|
|
20
|
+
|
|
21
|
+
// Check if the sum of the root node is correct after the update
|
|
22
|
+
expect(segmentTree.root?.sum).toBe(22);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should query sum by range correctly', () => {
|
|
26
|
+
// Check if the sum within a specific range is correct
|
|
27
|
+
expect(segmentTree.querySumByRange(1, 3)).toBe(9); // 2 + 3 + 4 = 9
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should handle edge cases for querySumByRange', () => {
|
|
31
|
+
// Check behavior when the range goes beyond boundaries
|
|
32
|
+
expect(segmentTree.querySumByRange(0, 4)).toBe(15); // Valid range, should return sum of the specified range
|
|
33
|
+
expect(segmentTree.querySumByRange(3, 2)).toBe(NaN); // End index is less than start index, should return NaN
|
|
34
|
+
expect(segmentTree.querySumByRange(0, 10)).toBe(NaN); // Beyond upper bound, should return NaN
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should handle an empty input array', () => {
|
|
38
|
+
// Check behavior when dealing with an empty input array
|
|
39
|
+
const emptySegmentTree = new SegmentTree([]);
|
|
40
|
+
expect(emptySegmentTree.root).toBe(null);
|
|
41
|
+
expect(emptySegmentTree.querySumByRange(0, 2)).toBe(0); // Sum of an empty array should be 0
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should handle a single-element input array', () => {
|
|
45
|
+
// Check behavior when the input array contains a single element
|
|
46
|
+
const singleElementSegmentTree = new SegmentTree([42]);
|
|
47
|
+
expect(singleElementSegmentTree.root?.sum).toBe(42);
|
|
48
|
+
expect(singleElementSegmentTree.querySumByRange(0, 0)).toBe(42); // Range covering the only element should return that element's value
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import {HashMap} from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('HashMap', () => {
|
|
4
|
+
let hashMap: HashMap<string, number>;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
hashMap = new HashMap<string, number>();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should initialize correctly', () => {
|
|
11
|
+
expect(hashMap.size).toBe(0);
|
|
12
|
+
expect(hashMap.table.length).toBe(16);
|
|
13
|
+
expect(hashMap.loadFactor).toBe(0.75);
|
|
14
|
+
expect(hashMap.capacityMultiplier).toBe(2);
|
|
15
|
+
expect(hashMap.initialCapacity).toBe(16);
|
|
16
|
+
expect(hashMap.isEmpty()).toBe(true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should put and get values', () => {
|
|
20
|
+
hashMap.set('one', 1);
|
|
21
|
+
hashMap.set('two', 2);
|
|
22
|
+
hashMap.set('three', 3);
|
|
23
|
+
|
|
24
|
+
expect(hashMap.get('one')).toBe(1);
|
|
25
|
+
expect(hashMap.get('two')).toBe(2);
|
|
26
|
+
expect(hashMap.get('three')).toBe(3);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should handle key collisions', () => {
|
|
30
|
+
// Force a collision by setting two different keys to the same bucket
|
|
31
|
+
hashMap.hashFn = () => 0; // Override hash function to return the same index
|
|
32
|
+
hashMap.set('key1', 1);
|
|
33
|
+
hashMap.set('key2', 2);
|
|
34
|
+
|
|
35
|
+
expect(hashMap.get('key1')).toBe(1);
|
|
36
|
+
expect(hashMap.get('key2')).toBe(2);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should remove values', () => {
|
|
40
|
+
hashMap.set('one', 1);
|
|
41
|
+
hashMap.set('two', 2);
|
|
42
|
+
|
|
43
|
+
hashMap.remove('one');
|
|
44
|
+
expect(hashMap.get('one')).toBeUndefined();
|
|
45
|
+
expect(hashMap.size).toBe(1);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should clear the HashMap', () => {
|
|
49
|
+
hashMap.set('one', 1);
|
|
50
|
+
hashMap.set('two', 2);
|
|
51
|
+
|
|
52
|
+
hashMap.clear();
|
|
53
|
+
expect(hashMap.size).toBe(0);
|
|
54
|
+
expect(hashMap.isEmpty()).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should iterate over entries', () => {
|
|
58
|
+
hashMap.set('one', 1);
|
|
59
|
+
hashMap.set('two', 2);
|
|
60
|
+
hashMap.set('three', 3);
|
|
61
|
+
|
|
62
|
+
const entries = Array.from(hashMap.entries());
|
|
63
|
+
expect(entries).toEqual(
|
|
64
|
+
expect.arrayContaining([
|
|
65
|
+
['one', 1],
|
|
66
|
+
['two', 2],
|
|
67
|
+
['three', 3]
|
|
68
|
+
])
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should resize the table when load factor is exceeded', () => {
|
|
73
|
+
// Set a small initial capacity for testing resizing
|
|
74
|
+
hashMap = new HashMap<string, number>(4, 0.5);
|
|
75
|
+
|
|
76
|
+
hashMap.set('one', 1);
|
|
77
|
+
hashMap.set('two', 2);
|
|
78
|
+
hashMap.set('three', 3);
|
|
79
|
+
hashMap.set('four', 4); // This should trigger a resize
|
|
80
|
+
|
|
81
|
+
expect(hashMap.table.length).toBe(8);
|
|
82
|
+
expect(hashMap.get('one')).toBe(1);
|
|
83
|
+
expect(hashMap.get('two')).toBe(2);
|
|
84
|
+
expect(hashMap.get('three')).toBe(3);
|
|
85
|
+
expect(hashMap.get('four')).toBe(4);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should allow using a custom hash function', () => {
|
|
89
|
+
const customHashFn = () => {
|
|
90
|
+
// A simple custom hash function that always returns 0
|
|
91
|
+
return 0;
|
|
92
|
+
};
|
|
93
|
+
hashMap = new HashMap<string, number>(16, 0.75, customHashFn);
|
|
94
|
+
|
|
95
|
+
hashMap.set('one', 1);
|
|
96
|
+
hashMap.set('two', 2);
|
|
97
|
+
|
|
98
|
+
expect(hashMap.get('one')).toBe(1);
|
|
99
|
+
expect(hashMap.get('two')).toBe(2);
|
|
100
|
+
// Since the custom hash function always returns 0, these keys will collide.
|
|
101
|
+
// Make sure they are stored separately.
|
|
102
|
+
expect(hashMap.table[0].length).toBe(2);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {HashTableNode, HashTable} from '../../../../src';
|
|
2
2
|
|
|
3
3
|
describe('HashNode', () => {
|
|
4
4
|
it('should create a HashNode with key and value', () => {
|
|
5
5
|
const key = 'testKey';
|
|
6
6
|
const value = 'testValue';
|
|
7
|
-
const hashNode = new
|
|
7
|
+
const hashNode = new HashTableNode(key, value);
|
|
8
8
|
|
|
9
9
|
expect(hashNode.key).toBe(key);
|
|
10
10
|
expect(hashNode.val).toBe(value);
|
|
@@ -16,9 +16,9 @@ describe('HashTable', () => {
|
|
|
16
16
|
it('should initialize with default capacity', () => {
|
|
17
17
|
const hashTable = new HashTable<string, string>();
|
|
18
18
|
|
|
19
|
-
expect(hashTable.capacity).toBe(
|
|
19
|
+
expect(hashTable.capacity).toBe(16);
|
|
20
20
|
expect(hashTable.size).toBe(0);
|
|
21
|
-
expect(hashTable.buckets.length).toBe(
|
|
21
|
+
expect(hashTable.buckets.length).toBe(16);
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
it('should initialize with custom capacity', () => {
|
|
@@ -35,7 +35,7 @@ describe('HashTable', () => {
|
|
|
35
35
|
const key = 'testKey';
|
|
36
36
|
const value = 'testValue';
|
|
37
37
|
|
|
38
|
-
hashTable.
|
|
38
|
+
hashTable.set(key, value);
|
|
39
39
|
const retrievedValue = hashTable.get(key);
|
|
40
40
|
|
|
41
41
|
expect(retrievedValue).toBe(value);
|
|
@@ -48,8 +48,8 @@ describe('HashTable', () => {
|
|
|
48
48
|
const key2 = 'testKey2';
|
|
49
49
|
const value2 = 'testValue2';
|
|
50
50
|
|
|
51
|
-
hashTable.
|
|
52
|
-
hashTable.
|
|
51
|
+
hashTable.set(key1, value1);
|
|
52
|
+
hashTable.set(key2, value2);
|
|
53
53
|
|
|
54
54
|
const retrievedValue1 = hashTable.get(key1);
|
|
55
55
|
const retrievedValue2 = hashTable.get(key2);
|
|
@@ -64,8 +64,8 @@ describe('HashTable', () => {
|
|
|
64
64
|
const initialValue = 'testValue1';
|
|
65
65
|
const updatedValue = 'testValue2';
|
|
66
66
|
|
|
67
|
-
hashTable.
|
|
68
|
-
hashTable.
|
|
67
|
+
hashTable.set(key, initialValue);
|
|
68
|
+
hashTable.set(key, updatedValue);
|
|
69
69
|
|
|
70
70
|
const retrievedValue = hashTable.get(key);
|
|
71
71
|
|
|
@@ -86,7 +86,7 @@ describe('HashTable', () => {
|
|
|
86
86
|
const key = 'testKey';
|
|
87
87
|
const value = 'testValue';
|
|
88
88
|
|
|
89
|
-
hashTable.
|
|
89
|
+
hashTable.set(key, value);
|
|
90
90
|
hashTable.remove(key);
|
|
91
91
|
|
|
92
92
|
const retrievedValue = hashTable.get(key);
|
|
@@ -95,3 +95,90 @@ describe('HashTable', () => {
|
|
|
95
95
|
expect(hashTable.size).toBe(0);
|
|
96
96
|
});
|
|
97
97
|
});
|
|
98
|
+
|
|
99
|
+
describe('HashTable', () => {
|
|
100
|
+
let hashTable: HashTable<string, number>;
|
|
101
|
+
|
|
102
|
+
beforeEach(() => {
|
|
103
|
+
hashTable = new HashTable<string, number>();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should insert and retrieve values correctly', () => {
|
|
107
|
+
hashTable.set('one', 1);
|
|
108
|
+
hashTable.set('two', 2);
|
|
109
|
+
|
|
110
|
+
expect(hashTable.get('one')).toBe(1);
|
|
111
|
+
expect(hashTable.get('two')).toBe(2);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should update values correctly', () => {
|
|
115
|
+
hashTable.set('one', 1);
|
|
116
|
+
expect(hashTable.get('one')).toBe(1);
|
|
117
|
+
|
|
118
|
+
hashTable.set('one', 100); // Update the value
|
|
119
|
+
expect(hashTable.get('one')).toBe(100);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should handle collisions correctly', () => {
|
|
123
|
+
hashTable = new HashTable<string, number>(1); // Set a small capacity to force collisions
|
|
124
|
+
hashTable.set('one', 1);
|
|
125
|
+
hashTable.set('two', 2);
|
|
126
|
+
|
|
127
|
+
expect(hashTable.get('one')).toBe(1);
|
|
128
|
+
expect(hashTable.get('two')).toBe(2);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should remove values correctly', () => {
|
|
132
|
+
hashTable.set('one', 1);
|
|
133
|
+
hashTable.set('two', 2);
|
|
134
|
+
hashTable.remove('one');
|
|
135
|
+
|
|
136
|
+
expect(hashTable.get('one')).toBeUndefined();
|
|
137
|
+
expect(hashTable.get('two')).toBe(2);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should handle non-existent keys correctly', () => {
|
|
141
|
+
expect(hashTable.get('non-existent')).toBeUndefined();
|
|
142
|
+
hashTable.remove('non-existent'); // Removing a non-existent key should not cause errors
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should handle custom hash function correctly', () => {
|
|
146
|
+
// const customHashFn = () => {
|
|
147
|
+
// // Custom hash function that returns a fixed value for all keys
|
|
148
|
+
// return 42;
|
|
149
|
+
// };
|
|
150
|
+
|
|
151
|
+
hashTable = new HashTable<string, number>(16);
|
|
152
|
+
hashTable.set('one', 1);
|
|
153
|
+
expect(hashTable.get('one')).toBe(1);
|
|
154
|
+
expect(hashTable.get('two')).toBeUndefined();
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should expand when load factor exceeds threshold', () => {
|
|
158
|
+
hashTable = new HashTable<string, number>(2); // Set a small capacity to trigger expansion
|
|
159
|
+
hashTable.set('one', 1);
|
|
160
|
+
hashTable.set('two', 2);
|
|
161
|
+
hashTable.set('three', 3); // This should trigger an expansion
|
|
162
|
+
|
|
163
|
+
expect(hashTable.capacity).toBe(16);
|
|
164
|
+
expect(hashTable.get('one')).toBe(1);
|
|
165
|
+
expect(hashTable.get('two')).toBe(2);
|
|
166
|
+
expect(hashTable.get('three')).toBe(3);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('HashTable performance', function () {
|
|
171
|
+
it('Items set performance', function () {
|
|
172
|
+
const mag = 100000;
|
|
173
|
+
const ht = new HashTable();
|
|
174
|
+
// const s = performance.now();
|
|
175
|
+
for (let i = 0; i < mag; i++) {
|
|
176
|
+
ht.set(i, i);
|
|
177
|
+
}
|
|
178
|
+
// const s1 = performance.now();
|
|
179
|
+
const map = new Map();
|
|
180
|
+
for (let i = 0; i < mag; i++) {
|
|
181
|
+
map.set(i, i);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
@@ -356,7 +356,7 @@ describe('DoublyLinkedList Performance Test', () => {
|
|
|
356
356
|
for (let i = 0; i < magnitude.LINEAR; i++) {
|
|
357
357
|
list.shift();
|
|
358
358
|
}
|
|
359
|
-
expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR *
|
|
359
|
+
expect(performance.now() - startPopTime).toBeLessThan(bigO.LINEAR * 100);
|
|
360
360
|
|
|
361
361
|
expect(list.pop()).toBeUndefined();
|
|
362
362
|
expect(list.length).toBe(0);
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import {SkipList} from '../../../../src';
|
|
2
|
+
|
|
3
|
+
describe('SkipList', () => {
|
|
4
|
+
let skipList: SkipList<number, string>;
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
skipList = new SkipList<number, string>();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should insert and retrieve elements correctly', () => {
|
|
11
|
+
skipList.add(1, 'One');
|
|
12
|
+
skipList.add(2, 'Two');
|
|
13
|
+
skipList.add(3, 'Three');
|
|
14
|
+
|
|
15
|
+
expect(skipList.get(1)).toBe('One');
|
|
16
|
+
expect(skipList.get(2)).toBe('Two');
|
|
17
|
+
expect(skipList.get(3)).toBe('Three');
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should return undefined for non-existent keys', () => {
|
|
21
|
+
skipList.add(1, 'One');
|
|
22
|
+
skipList.add(2, 'Two');
|
|
23
|
+
|
|
24
|
+
expect(skipList.get(3)).toBeUndefined();
|
|
25
|
+
expect(skipList.get(0)).toBeUndefined();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should remove elements correctly', () => {
|
|
29
|
+
skipList.add(1, 'One');
|
|
30
|
+
skipList.add(2, 'Two');
|
|
31
|
+
skipList.add(3, 'Three');
|
|
32
|
+
|
|
33
|
+
skipList.remove(2);
|
|
34
|
+
|
|
35
|
+
expect(skipList.get(2)).toBeUndefined(); // 修改这里的断言
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should handle random data correctly', () => {
|
|
39
|
+
const randomData: Array<[number, string]> = [
|
|
40
|
+
[5, 'Five'],
|
|
41
|
+
[1, 'One'],
|
|
42
|
+
[3, 'Three'],
|
|
43
|
+
[2, 'Two'],
|
|
44
|
+
[4, 'Four']
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
for (const [key, value] of randomData) {
|
|
48
|
+
skipList.add(key, value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
expect(skipList.get(3)).toBe('Three');
|
|
52
|
+
expect(skipList.get(5)).toBe('Five');
|
|
53
|
+
expect(skipList.get(4)).toBe('Four');
|
|
54
|
+
});
|
|
55
|
+
});
|