UNPKG

4.8 kBJavaScriptView Raw
1import { NullPointerException } from "../exception/NotNullException";
2import LinkList from "../linklist/LinkList";
3import { hash, toString } from "../util";
4function defineHashNodeToString(node) {
5 Object.defineProperty(node, "toString", {
6 value: function () {
7 return JSON.stringify(this);
8 },
9 });
10}
11export class HashTable {
12 constructor(size = HashTable.DEFAULT_TABLE_SIZE) {
13 this.buckets = Array(size).fill(null).map(() => new LinkList());
14 this.count = 0;
15 this.keys = {};
16 this.threshold = size * HashTable.LOADFACTOR;
17 }
18 static setDefaultTableSize(size) {
19 this.DEFAULT_TABLE_SIZE = size;
20 }
21 get Count() {
22 return this.count;
23 }
24 get TableSize() {
25 return this.buckets.length;
26 }
27 put(key, value) {
28 if (key === null || key === undefined) {
29 throw new NullPointerException();
30 }
31 const tempKey = toString(key);
32 const hashed = hash(tempKey);
33 let keyHash = this.mod(hashed);
34 let bucketLinkedList = this.buckets[keyHash];
35 const node = bucketLinkedList.findNode(item => item.key === key);
36 if (node) {
37 node.Value.value = value;
38 return;
39 }
40 if (this.count >= this.threshold) {
41 this.rehash();
42 keyHash = this.mod(hashed);
43 bucketLinkedList = this.buckets[keyHash];
44 }
45 this.keys[tempKey] = keyHash;
46 bucketLinkedList.append({
47 key,
48 value,
49 });
50 this.count++;
51 return this;
52 }
53 get(key) {
54 const tempKey = toString(key);
55 const hashed = hash(tempKey);
56 const keyHash = this.mod(hashed);
57 const bucketLinkedList = this.buckets[keyHash];
58 const node = bucketLinkedList.findNode(item => item.key === key);
59 return node ? node.Value.value : null;
60 }
61 remove(key) {
62 const tempKey = toString(key);
63 const hashed = hash(tempKey);
64 const keyHash = this.mod(hashed);
65 const bucketLinkedList = this.buckets[keyHash];
66 const node = bucketLinkedList.findNode(item => item.key === key);
67 if (node) {
68 this.count--;
69 return bucketLinkedList.deleteNode(node.Value);
70 }
71 return false;
72 }
73 contains(key) {
74 return this.get(key) !== null;
75 }
76 getKeys() {
77 return Object.keys(this.keys);
78 }
79 getOrignalKeys() {
80 const arr = new Array(this.count);
81 this.iterate((item, index) => {
82 arr[index] = item.key;
83 });
84 return arr;
85 }
86 values() {
87 const arr = new Array(this.count);
88 this.iterate((item, index) => {
89 arr[index] = item.value;
90 });
91 return arr;
92 }
93 clear() {
94 this.buckets.length = 0;
95 this.keys = {};
96 this.count = 0;
97 this.buckets = Array(HashTable.DEFAULT_TABLE_SIZE)
98 .fill(null).map(() => new LinkList());
99 }
100 getHashKey(key) {
101 const tempKey = toString(key);
102 return this.keys[tempKey];
103 }
104 toString() {
105 const arr = [];
106 this.iterate(item => {
107 const node = {
108 key: item.key,
109 value: item.value,
110 };
111 defineHashNodeToString(node);
112 arr.push(node);
113 });
114 return arr.toString();
115 }
116 iterate(fn) {
117 let iterateFlag = 0;
118 for (let i = 0, count = this.buckets.length; i < count; i++) {
119 const linkArr = this.buckets[i].toArray();
120 const arrCount = iterateFlag;
121 for (let j = arrCount, addCount = arrCount + linkArr.length; j < addCount; j++) {
122 fn(linkArr[j - arrCount].Value, iterateFlag);
123 iterateFlag++;
124 }
125 }
126 }
127 rehash() {
128 const oldBuckets = this.buckets;
129 const newCapacity = oldBuckets.length * 2 + 1;
130 const newBuckets = Array(newCapacity).fill(null).map(() => new LinkList());
131 this.buckets = newBuckets;
132 this.keys = {};
133 for (let i = 0, oldLen = oldBuckets.length; i < oldLen; i++) {
134 oldBuckets[i].toArray().forEach(item => {
135 const data = item.Value;
136 const hashed = hash(toString(data.key));
137 const keyHash = this.mod(hashed);
138 newBuckets[keyHash].append(data);
139 this.keys[toString(data.key)] = keyHash;
140 });
141 }
142 oldBuckets.length = 0;
143 this.threshold = newCapacity * HashTable.LOADFACTOR;
144 }
145 mod(hashed) {
146 const modulo = hashed % this.buckets.length;
147 return hashed < 0 ? modulo * -1 : modulo;
148 }
149}
150HashTable.DEFAULT_TABLE_SIZE = 11;
151HashTable.LOADFACTOR = 0.75;