-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhash-table.ts
145 lines (127 loc) · 3.52 KB
/
hash-table.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { Pair } from "@/types/pair";
import { Comparator } from "@/utils";
import { LinkedList } from "../linked-list/";
/**
* Hash table (also known as a hash map) is a data structure that allows efficient
* insertion, deletion, and retrieval of key-value pairs.
* It uses a hash function to map keys to indices in an array, where the corresponding values are stored.
* The hash function takes the key as input and computes a hash code, which is used to determine the index.
*/
export class HashTable<Value> {
private buckets: LinkedList<Pair<Value>>[];
private keys: Record<string, number> = {};
constructor(size = 32) {
// By default compares by value
const pairComparator = Comparator.comparing(
(pair: Pair<Value>) => pair.value
);
// Create hash table of certain size and fill each bucket with empty linked list.
this.buckets = Array(size)
.fill(null)
.map(() => new LinkedList<Pair<Value>>(pairComparator));
}
/**
* Generate number to use as index in the hash table.
* @param key - The key of the hash table.
* @returns number.
*/
private hash(key: string): number {
let hash = 0;
for (let i = 0; i < key.length; i++) {
hash = (hash + key.charCodeAt(i) * 23) % this.buckets.length;
}
return hash;
}
/**
* Adds or update a key/value pair to the hash table.
* @param key
* @param value
* @returns
*/
public set(key: string, value: Value): HashTable<Value> {
const index = this.hash(key);
this.keys[key] = index;
const bucketLinkedList = this.buckets[index];
const node = bucketLinkedList.find({
callback: (item) => item.key === key,
});
if (!node) {
// Insert new node.
bucketLinkedList.append({ key, value });
} else {
// Update value of existing node.
node.value.value = value;
}
return this;
}
/**
* Returns a node value with the given key.
* @param key - The given key.
* @returns node value or null.
*/
public get(key: string) {
const index = this.hash(key);
const bucketLinkedList = this.buckets[index];
const node = bucketLinkedList.find({
callback: (item) => item.key === key,
});
if (node) {
return node.value.value;
}
return null;
}
/**
* Removes item by the given key.
* @param key - The key to remove.
* @returns null or removed key.
*/
public remove(key: string) {
const index = this.hash(key);
delete this.keys[key];
const bucketLinkedList = this.buckets[index];
const node = bucketLinkedList.find({
callback: (item) => item.key === key,
});
if (node) {
return bucketLinkedList.delete(node.value);
}
return null;
}
/**
* Checks if the given key is exists.
* @param key - The given key.
* @returns true or false.
*/
public has(key: string): boolean {
return key in this.keys;
}
/**
* Returns all the keys.
* @returns array of keys.
*/
public getKeys(): string[] {
return Object.keys(this.keys);
}
/**
* Returns all hash table values.
* @returns array of values.
*/
getValues(): Value[] {
return this.buckets.reduce(
(values: Value[], bucket: LinkedList<Pair<Value>>) => {
const bucketValues = bucket
.toArray()
.map((linkedListNode) => linkedListNode.value.value);
return values.concat(bucketValues as Value);
},
[]
);
}
/**
* Lenght of the hash table.
* @returns number
*/
public size(): number {
return this.buckets.length;
}
}