data-structure-typed 1.33.6 → 1.33.8

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.
Files changed (51) hide show
  1. package/.github/workflows/ci.yml +1 -0
  2. package/CHANGELOG.md +1 -1
  3. package/README.md +42 -38
  4. package/coverage/coverage-final.json +64 -63
  5. package/coverage/coverage-summary.json +8 -7
  6. package/dist/data-structures/binary-tree/segment-tree.js +24 -6
  7. package/dist/data-structures/binary-tree/segment-tree.js.map +1 -1
  8. package/dist/data-structures/hash/hash-map.js +306 -0
  9. package/dist/data-structures/hash/hash-map.js.map +1 -0
  10. package/dist/data-structures/hash/hash-table.js +128 -38
  11. package/dist/data-structures/hash/hash-table.js.map +1 -1
  12. package/dist/data-structures/hash/index.js +1 -0
  13. package/dist/data-structures/hash/index.js.map +1 -1
  14. package/dist/data-structures/linked-list/skip-linked-list.js +122 -5
  15. package/dist/data-structures/linked-list/skip-linked-list.js.map +1 -1
  16. package/dist/types/data-structures/hash.js +3 -0
  17. package/dist/types/data-structures/hash.js.map +1 -0
  18. package/dist/types/data-structures/index.js +1 -0
  19. package/dist/types/data-structures/index.js.map +1 -1
  20. package/docs/index.html +35 -37
  21. package/docs/modules.html +10 -4
  22. package/lib/data-structures/binary-tree/segment-tree.d.ts +4 -4
  23. package/lib/data-structures/binary-tree/segment-tree.js +30 -14
  24. package/lib/data-structures/hash/hash-map.d.ts +56 -0
  25. package/lib/data-structures/hash/hash-map.js +167 -0
  26. package/lib/data-structures/hash/hash-table.d.ts +67 -23
  27. package/lib/data-structures/hash/hash-table.js +154 -52
  28. package/lib/data-structures/hash/index.d.ts +1 -0
  29. package/lib/data-structures/hash/index.js +1 -0
  30. package/lib/data-structures/linked-list/skip-linked-list.d.ts +60 -1
  31. package/lib/data-structures/linked-list/skip-linked-list.js +136 -1
  32. package/lib/types/data-structures/hash.d.ts +1 -0
  33. package/lib/types/data-structures/hash.js +1 -0
  34. package/lib/types/data-structures/index.d.ts +1 -0
  35. package/lib/types/data-structures/index.js +1 -0
  36. package/package.json +22 -22
  37. package/src/data-structures/binary-tree/segment-tree.ts +32 -14
  38. package/src/data-structures/hash/hash-map.ts +203 -0
  39. package/src/data-structures/hash/hash-table.ts +176 -56
  40. package/src/data-structures/hash/index.ts +1 -0
  41. package/src/data-structures/linked-list/skip-linked-list.ts +166 -1
  42. package/src/types/data-structures/hash.ts +1 -0
  43. package/src/types/data-structures/index.ts +1 -0
  44. package/test/integration/index.html +26 -18
  45. package/test/unit/data-structures/binary-tree/segment-tree.test.ts +50 -0
  46. package/test/unit/data-structures/hash/hash-map.test.ts +104 -0
  47. package/test/unit/data-structures/hash/hash-table.test.ts +97 -10
  48. package/test/unit/data-structures/linked-list/skip-list.test.ts +55 -0
  49. package/umd/bundle.min.js +1 -1
  50. package/umd/bundle.min.js.map +1 -1
  51. package/tsconfig.prod.json +0 -25
@@ -1 +1,166 @@
1
- export class SkipLinkedList {}
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;
@@ -13,3 +13,4 @@ export * from './heap';
13
13
  export * from './singly-linked-list';
14
14
  export * from './doubly-linked-list';
15
15
  export * from './navigator';
16
+ export * from './hash';
@@ -13,30 +13,38 @@
13
13
  </div>
14
14
  <script defer>
15
15
  const $modules = document.querySelector('.modules');
16
- const $avlTree = document.createElement('li');
17
- const $avlTreeSpan = document.createElement('span');
18
- $avlTreeSpan.innerText = 'AVLTree';
19
- $avlTree.append($avlTreeSpan);
20
- const {AVLTree, Queue} = dataStructureTyped;
21
- const avlTree = new AVLTree();
22
16
 
23
- avlTree.add(1, 1);
24
- console.log(avlTree.BFS());
25
- $modules.append($avlTree);
26
17
 
18
+ try {
19
+ const {AVLTree, Queue} = window.dataStructureTyped;
20
+ const avlTree = new AVLTree();
21
+ const $avlTree = document.createElement('li');
22
+ const $avlTreeSpan = document.createElement('span');
23
+ $avlTreeSpan.innerText = 'AVLTree';
24
+ $avlTree.append($avlTreeSpan);
25
+ avlTree.add(1, 1);
26
+ console.log(avlTree.BFS());
27
+ $modules.append($avlTree);
27
28
 
28
- const queue = new Queue();
29
- for (let i = 0; i < 1000000; i++) {
30
- queue.enqueue(i);
31
- }
32
- let last = 0;
33
- const startTime = performance.now();
34
29
 
35
- for (let i = 0; i < 1000000; i++) {
36
- last = queue.dequeue();
30
+ const queue = new Queue();
31
+ for (let i = 0; i < 1000000; i++) {
32
+ queue.enqueue(i);
33
+ }
34
+ let last = 0;
35
+ const startTime = performance.now();
36
+
37
+ for (let i = 0; i < 1000000; i++) {
38
+ last = queue.dequeue();
39
+ }
40
+
41
+ console.log(performance.now() - startTime);
42
+
43
+ }
44
+ catch (e) {
45
+ console.error(e);
37
46
  }
38
47
 
39
- console.log(performance.now() - startTime);
40
48
  </script>
41
49
 
42
50
  </body>
@@ -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 {HashNode, HashTable} from '../../../../src';
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 HashNode(key, value);
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(1000);
19
+ expect(hashTable.capacity).toBe(16);
20
20
  expect(hashTable.size).toBe(0);
21
- expect(hashTable.buckets.length).toBe(1000);
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.put(key, value);
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.put(key1, value1);
52
- hashTable.put(key2, value2);
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.put(key, initialValue);
68
- hashTable.put(key, updatedValue);
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.put(key, value);
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
+ });
@@ -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
+ });