Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 446bbab

Browse files
committed
chapter 8: dictionary and hash table
1 parent fe6f722 commit 446bbab

13 files changed

+619
-0
lines changed

‎src/06-linked-list/linked-list_.js‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ class LinkedList {
126126
return this.#size;
127127
}
128128

129+
forEach(callback) {
130+
let current = this.#head;
131+
let index = 0;
132+
while (current) {
133+
callback(current.data, index);
134+
current = current.next;
135+
index++;
136+
}
137+
}
138+
129139
toString() {
130140
let current = this.#head;
131141
let objString = '';
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// src/08-dictionary-hash/01-using-dictionary-class.js
2+
3+
const Dictionary = require('./dictionary');
4+
5+
const translations = new Dictionary();
6+
7+
// Add some translations - English to Portuguese
8+
translations.set("hello", "olá");
9+
translations.set("thank you", "obrigado");
10+
translations.set("book", "livro");
11+
translations.set("cat", "gato");
12+
translations.set("computer", "computador");
13+
14+
// User interaction
15+
function translateWord(word) {
16+
if (translations.hasKey(word)) {
17+
const translation = translations.get(word);
18+
console.log(`The translation of "${word}" is "${translation}"`);
19+
} else {
20+
console.log(`Sorry, no translation found for "${word}"`);
21+
}
22+
}
23+
24+
// Example usage
25+
translateWord("hello"); // Output: The translation of "hello" is "olá"
26+
translateWord("dog"); // Output: Sorry, no translation found for "dog"
27+
28+
// Get all translations
29+
console.log("All translations:", translations.values());
30+
// All translations: [ 'olá', 'obrigado', 'livro', 'gato', 'computador' ]
31+
32+
// Get all words
33+
console.log("All words:", translations.keys());
34+
// All words: [ 'hello', 'thank you', 'book', 'cat', 'computer' ]
35+
36+
// Iterate through all translations
37+
translations.forEach((value, key) => {
38+
console.log(`${key}: ${value}`);
39+
});
40+
41+
42+
// to see the output of this file use the command: node src/08-dictionary-hash/01-using-dictionary-class.js
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// src/08-dictionary-hash/02-using-map-class.js
2+
3+
const translations = new Map();
4+
5+
// Add some translations - English to Portuguese
6+
translations.set("hello", "olá");
7+
translations.set("thank you", "obrigado");
8+
translations.set("book", "livro");
9+
translations.set("cat", "gato");
10+
translations.set("computer", "computador");
11+
12+
// User interaction
13+
function translateWord(word) {
14+
if (translations.has(word)) {
15+
const translation = translations.get(word);
16+
console.log(`The translation of "${word}" is "${translation}"`);
17+
} else {
18+
console.log(`Sorry, no translation found for "${word}"`);
19+
}
20+
}
21+
22+
// Example usage
23+
translateWord("hello"); // Output: The translation of "hello" is "olá"
24+
translateWord("dog"); // Output: Sorry, no translation found for "dog"
25+
26+
// Get all translations
27+
console.log("All translations:", translations.values());
28+
// All translations: [ 'olá', 'obrigado', 'livro', 'gato', 'computador' ]
29+
30+
// Get all words
31+
console.log("All words:", translations.keys());
32+
// All words: [ 'hello', 'thank you', 'book', 'cat', 'computer' ]
33+
34+
// Iterate through all translations
35+
translations.forEach((value, key) => {
36+
console.log(`${key}: ${value}`);
37+
});
38+
39+
40+
// to see the output of this file use the command: node src/08-dictionary-hash/01-using-dictionary-class.js
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const privateData = new WeakMap();
2+
3+
class Person {
4+
constructor(name, age) {
5+
this.name = name;
6+
this.age = age;
7+
privateData.set(this, { ssn: 'XXX-XX-XXXX', medicalHistory: [] });
8+
}
9+
10+
getSSN() {
11+
return privateData.get(this)?.ssn;
12+
}
13+
}
14+
15+
const alice = new Person("Penelope", 20);
16+
console.log(alice.name); // Penelope
17+
console.log(alice.getSSN()); // XXX-XX-XXXX
18+
19+
// Try to access private data
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// src/08-dictionary-hash/04-using-hashmap-class.js
2+
3+
const HashTable = require('./hash-table');
4+
5+
const addressBook = new HashTable();
6+
7+
// Add contacts
8+
addressBook.put('Gandalf', 'gandalf@email.com');
9+
addressBook.put('John', 'johnsnow@email.com');
10+
addressBook.put('Tyrion', 'tyrion@email.com');
11+
12+
// Retrieve the hash code of a contact
13+
console.log(addressBook.hash('Gandalf')); // 19
14+
console.log(addressBook.hash('John')); // 29
15+
console.log(addressBook.hash('Tyrion')); // 16
16+
17+
// Retrieve contacts
18+
console.log(addressBook.get('Gandalf')); // gandalf@email.com
19+
console.log(addressBook.get('Loiane')); // undefined
20+
21+
// Remove contacts
22+
console.log(addressBook.remove('Gandalf')); // true
23+
console.log(addressBook.get('Gandalf')); // undefined
24+
25+
26+
// to see the output of this file use the command: node src/08-dictionary-hash/04-using-hashmap-class.js
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// src/08-dictionary-hash/05-hashmap-collision.js
2+
3+
const HashTable = require('./hash-table');
4+
5+
const addressBook = new HashTable();
6+
7+
// Add contacts
8+
addressBook.put('Ygritte', 'ygritte@email.com');
9+
addressBook.put('Jonathan', 'jonathan@email.com');
10+
addressBook.put('Jamie', 'jamie@email.com');
11+
addressBook.put('Jack', 'jack@email.com');
12+
addressBook.put('Jasmine', 'jasmine@email.com');
13+
addressBook.put('Jake', 'jake@email.com');
14+
addressBook.put('Nathan', 'nathan@email.com');
15+
addressBook.put('Athelstan', 'athelstan@email.com');
16+
addressBook.put('Sue', 'sue@email.com');
17+
addressBook.put('Aethelwulf', 'aethelwulf@email.com');
18+
addressBook.put('Sargeras', 'sargeras@email.com');
19+
20+
// Retrieve the hash code of a contact
21+
console.log(addressBook.hash('Ygritte'), '- Ygritte'); // 4
22+
console.log(addressBook.hash('Jonathan'), '- Jonathan'); // 5
23+
console.log(addressBook.hash('Jamie'), '- Jamie'); // 5
24+
console.log(addressBook.hash('Jack'), '- Jack'); // 7
25+
console.log(addressBook.hash('Jasmine'), '- Jasmine'); // 8
26+
console.log(addressBook.hash('Jake'), '- Jake'); // 9
27+
console.log(addressBook.hash('Nathan'), '- Nathan'); // 10
28+
console.log(addressBook.hash('Athelstan'), '- Athelstan'); // 7
29+
console.log(addressBook.hash('Sue'), '- Sue'); // 5
30+
console.log(addressBook.hash('Aethelwulf'), '- Aethelwulf'); // 5
31+
console.log(addressBook.hash('Sargeras'), '- Sargeras'); // 10
32+
33+
console.log(addressBook.toString());
34+
// {4 => ygritte@email.com}
35+
// {5 => aethelwulf@email.com}
36+
// {7 => athelstan@email.com}
37+
// {8 => jasmine@email.com}
38+
// {9 => jake@email.com}
39+
// {10 => sargeras@email.com}
40+
41+
42+
// to see the output of this file use the command: node src/08-dictionary-hash/05-hashmap-collision.js

‎src/08-dictionary-hash/dictionary.js‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// src/08-dictionary-hash/dictionary.js
2+
3+
class Dictionary {
4+
#items = {};
5+
#size = 0;
6+
7+
hasKey(key) {
8+
return this.#items[this.#elementToString(key)] != null;
9+
}
10+
11+
set(key, value) {
12+
if (key != null && value != null) {
13+
const tableKey = this.#elementToString(key);
14+
this.#items[tableKey] = value;
15+
this.#size++;
16+
return true;
17+
}
18+
return false;
19+
}
20+
21+
delete(key) {
22+
if (this.hasKey(key)) {
23+
delete this.#items[this.#elementToString(key)];
24+
this.#size--;
25+
return true;
26+
}
27+
return false;
28+
}
29+
30+
get(key) {
31+
return this.#items[this.#elementToString(key)];
32+
}
33+
34+
values() {
35+
return Object.values(this.#items);
36+
}
37+
38+
keys() {
39+
return Object.keys(this.#items);
40+
}
41+
42+
forEach(callbackFn) {
43+
for (const key in this.#items) {
44+
if (this.#items.hasOwnProperty(key)) {
45+
callbackFn(this.#items[key], key);
46+
}
47+
}
48+
}
49+
50+
#elementToString(data) {
51+
if (typeof data === 'object' && data !== null) {
52+
return JSON.stringify(data);
53+
} else {
54+
return data.toString();
55+
}
56+
}
57+
}
58+
59+
module.exports = Dictionary;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// src/08-dictionary-hash/hash-table-linear-probing.js
2+
3+
class HashTableLinearProbing {
4+
#table = [];
5+
6+
#loseLoseHashCode(key) {
7+
if (typeof key !== 'string') {
8+
key = this.#elementToString(key);
9+
}
10+
const calcASCIIValue = (acc, char) => acc + char.charCodeAt(0);
11+
const hash = key.split('').reduce((acc, char) => calcASCIIValue, 0);
12+
return hash % 37; // mod to reduce the hash code
13+
}
14+
15+
#djb2HashCode(key) {
16+
if (typeof key !== 'string') {
17+
key = this.#elementToString(key);
18+
}
19+
const calcASCIIValue = (acc, char) => (acc * 33) + char.charCodeAt(0);
20+
const hash = key.split('').reduce((acc, char) => calcASCIIValue, 5381);
21+
return hash % 1013;
22+
}
23+
24+
hash(key) {
25+
return this.#loseLoseHashCode(key);
26+
}
27+
28+
#elementToString(data) {
29+
if (typeof data === 'object' && data !== null) {
30+
return JSON.stringify(data);
31+
} else {
32+
return data.toString();
33+
}
34+
}
35+
36+
put(key, value) {
37+
if (key != null && value != null) {
38+
let index = this.hash(key);
39+
40+
// linear probing to find an empty slot
41+
while (this.#table[index] != null) {
42+
if (this.#table[index].key === key) {
43+
this.#table[index].value = value; // update existing key
44+
return true;
45+
}
46+
index++;
47+
index %= this.#table.length; // wrap around if end is reached
48+
}
49+
50+
this.#table[index] = {key, value};
51+
return true;
52+
}
53+
return false;
54+
}
55+
56+
get(key) {
57+
let index = this.hash(key);
58+
59+
// Linear probing to search for the key
60+
while (this.#table[index] != null) {
61+
if (this.#table[index].key === key) {
62+
return this.#table[index].value;
63+
}
64+
index++;
65+
index %= this.#table.length;
66+
}
67+
68+
return undefined; // key not found
69+
}
70+
71+
remove(key) {
72+
let index = this.hash(key);
73+
while (this.#table[index] != null) {
74+
if (this.#table[index].key === key) {
75+
delete this.#table[index];
76+
this.#verifyRemoveSideEffect(key, index);
77+
return true;
78+
}
79+
index++;
80+
index %= this.#table.length;
81+
}
82+
return false; // key not found
83+
}
84+
85+
#verifyRemoveSideEffect(key, removedPosition) {
86+
const size = this.#table.length;
87+
let index = removedPosition + 1;
88+
while (this.#table[index] != null) {
89+
const currentKey = this.#table[index].key;
90+
const currentHash = this.hash(currentKey);
91+
// check if the element should be repositioned
92+
if (currentHash <= removedPosition) {
93+
this.#table[removedPosition] = this.#table[index];
94+
delete this.#table[index];
95+
removedPosition = index;
96+
}
97+
index++;
98+
index %= size; // Wrap around if end is reached
99+
}
100+
}
101+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /