Dictionaries
Store [key, value] pairs
Then, we need to declare some methods that can be used by the mapping / dictionary.
- set(key,value): adds a new element to the dictionary.
- remove(key): remove the data value corresponding to the key value from the dictionary by using the key value.
- has(key): if a key value exists in this dictionary, it returns true; otherwise, it returns false.
- get(key): find a specific value through the key value and return it.
- clear(): delete all the elements in this dictionary.
- size(): returns the number of elements contained in the dictionary. Similar to the length attribute of an array.
- keys(): returns all the key names contained in the dictionary as an array.
- values(): returns all values contained in the dictionary as an array.
Hash table
HashTable class, also known as HashMap class, is a hash table implementation of Dictionary class.
The function of hash algorithm is to find a value in the data structure as soon as possible. If you use a hash function, you know the exact location of the value, so you can quickly retrieve the value.
The hash function gives a key value and returns the address of the value in the table
Then, add some methods to the class. We implement three basic methods for each class.
- put(key,value): adds a new item to the hash table (it can also update the hash table).
- remove(key): removes the value from the hash table based on the key value
- get(key): returns the specific value retrieved according to the key value
hash set
There is also an implementation called a hash set. A hash set consists of a set, but inserts
Hash functions are used when removing or getting elements. We can reuse all the code implemented in this chapter to implement the hash set,
The difference is that instead of adding key value pairs, only values are inserted without keys. For example, you can use a hash collection to store all data
English words (excluding their definitions). Like collections, hash collections store only unique, non repeating values.
Sometimes, some keys have the same hash value. When different values correspond to the same position in the hash table, we call it conflict.
A well performing hash function consists of several aspects: the time to insert and retrieve elements (i.e. performance), and of course, the low possibility of conflict.
A better hash function is djb2 (community scenario)
- Detach link
The separate link method includes creating a linked list for each position of the hash table and storing the elements in it. It is the of conflict resolution
The simplest method, but it requires additional storage space in addition to the HashTable instance. - Linear exploration
When you want to add a new element to a position in the table, if the index
If the position of index has been occupied, try the position of index+1. If the position of index+1 is also occupied, try
index+2, and so on. - Double hash method
/* - put(key,value): Add a new item to the hash table (you can also update the hash table). - remove(key): Removes a value from the hash table based on the key value. - get(key): Returns a specific value retrieved from a key value. */ // Given a key parameter, we can get a number according to the sum of ASCII code values of each character constituting the key, which is stored as a subscript. // Lose lose function function HashTable() { let table = [] let loseloseHashCode = function(key) { let hash = 0 for (let i = 0; i < key.length; i++) { hash += key.charCodeAt(i) } return hash % 37 } this.put = function(key, value) { let position = loseloseHashCode(key) console.log(position + '-' + key) console.log(position) table[position] = value } this.remove = function(key) { table[loseloseHashCode(key)] = undefined } this.get = function(key) { return table[loseloseHashCode(key)] } this.getTable = function(key) { return table } } // var hash = new HashTable(); // hash.put('Gandalf', '[email protected]'); // hash.put('John', '[email protected]'); // hash.put('Tyrion', '[email protected]'); // console.dir(hash.getTable()); // console.log(hash.getTable().length); // console.log(hash.get('Gandalf')); // console.log(hash.get('Loiane')); // hash.remove('Gandalf'); // console.log(hash.get('Gandalf')); // Key Conflict var hash = new HashTable(); hash.put('Gandalf', '[email protected]'); hash.put('John', '[email protected]'); hash.put('Tyrion', '[email protected]'); hash.put('Aaron', '[email protected]'); hash.put('Donnie', '[email protected]'); hash.put('Ana', '[email protected]'); hash.put('Jonathan', '[email protected]'); hash.put('Jamie', '[email protected]'); hash.put('Sue', '[email protected]'); hash.put('Mindy', '[email protected]'); hash.put('Paul', '[email protected]'); hash.put('Nathan', '[email protected]'); console.dir(hash.getTable());Split hash
let LinkedList = function() { let Node = function (element) { // Auxiliary class, which manages the pointer of the next element this.element = element this.next = null } let length = 0 let head = null // The chain from head to tail, and finally null // If the list is empty, the first element is added, or if the list is not empty, an element is appended to it this.append = function (element) { let node = new Node(element) let current if(head === null) { head = node // node's next is still null (1) } else { current = head while(current.next) { // In the second entry, the next value of the first entry is null, because (1), go directly (2) current = current.next // If there is a next one, replace it with the next one. Continue to search until the end. Next is null } current.next = node // Append element (2). The next element of the last node in the list is always null. } length++ // Update list length } this.toString = function () { let current = head let string = '' while(current) { string += current.element current = current.next } return string } this.isEmpty = function () { return length === 0 } this.size = function () { return length } this.getHead = function () { return head } this.insert = function (position, element) { if (position >= 0 && position <= length) { let node = new Node(element) let current = head let index = 0 if(position === 0) { // Head insertion node.next = current head = node } else { while(index++ < position) { previous = current // Record the element before the inserted element current = current.next // Currently points to the element after the inserted element } node.next = current // The next inserted element is the following element previous.next = node // The next element of the previous element of the inserted element is the inserted element } length++ return true } else { return false } } // There are also two scenarios for removing elements: the first is to remove the first element, and the second is to remove any element other than the first. // We want to implement two remove methods: the first is to remove an element from a specific location, and the second is to remove the element according to the value of the element this.removeAt = function (position) { // Boundary judgment if(position > -1 && position < length) { let current = head let previous let index = 0 if(position === 0) { head = current.next // Point to the next element } else { while( index++ < position) { previous = current // Record the element before the deleted element current = current.next // Currently points to the element after the deleted element } // previous.next originally pointed to current, // Now link previous to the next item of current: skip current, // To remove current previous.next = current.next } length-- return current.element // Returns the value of the next element } else { return null } } this.indexOf = function (element) { let current = head let index = 0 while(current) { if(element === current.element) { return index } index++ current = current.next } return -1 } this.remove = function (element) { let index = this.indexOf(element) return this.removeAt(index) } } // Detach link function HashTable() { let table = [] let ValuePair = function(key, value) { this.key = key this.value = value this.toString = function(){ return `[$-$]` } } let loseloseHashCode = function(key) { let hash = 0 for (let i = 0; i < key.length; i++) { hash += key.charCodeAt(i) } return hash % 37 } this.put = function(key, value) { let position = loseloseHashCode(key) if(!table[position]) { table[position] = new LinkedList() } table[position].append(new ValuePair(key, value)) } this.remove = function(key) { let position = loseloseHashCode[key] if(table[position] !== undefined) { let current = table[position].head while(current.next) { if(current.element.key === key) { table[position].remove(current.element) if(table[position].isEmpty()) { table[position] = undefined } return true } current = current.next } if(current.element.key === key) { table[position].remove(current.element) if(table[position].isEmpty()) { table[position] = undefined } return true } } return false } this.get = function(key) { let position = loseloseHashCode[key] if(table[position] !== undefined) { let current = table[position].head while(current.next) { if(current.element.key === key) { return current.element.value } current = current.next } if(current.element.key === key) { return current.element.value } } return undefined } this.print = function(key) { console.dir(table) let tables = table.filter(item=>item) console.log(tables) for (let i = 0; i < tables.length; i++) { console.log(`$-$`) } } } // Key Conflict var hash = new HashTable(); hash.put('Gandalf', '[email protected]'); hash.put('John', '[email protected]'); hash.put('Tyrion', '[email protected]'); hash.put('Aaron', '[email protected]'); hash.put('Donnie', '[email protected]'); hash.put('Ana', '[email protected]'); hash.put('Jonathan', '[email protected]'); hash.put('Jamie', '[email protected]'); hash.put('Sue', '[email protected]'); hash.put('Mindy', '[email protected]'); hash.put('Paul', '[email protected]'); hash.put('Nathan', '[email protected]'); hash.print()Linear exploration
// Linear exploration /* . When you want to add a new element to a position in the table, if the index If the position of index has been occupied, try the position of index+1. If the position of index+1 is also occupied, try index+2 And so on. */ function HashTable() { let table = [] let ValuePair = function(key, value) { this.key = key this.value = value this.toString = function(){ return `[$-$]` } } let loseloseHashCode = function(key) { let hash = 0 for (let i = 0; i < key.length; i++) { hash += key.charCodeAt(i) } return hash % 37 } this.put = function(key, value) { let position = loseloseHashCode(key) if(!table[position]) { table[position] = new ValuePair(key, value) } else{ let index = ++position while(table[index] !== undefined) { index++ } table[index] = new ValuePair(key, value) } } this.remove = function(key) { let position = loseloseHashCode[key] if(table[position] !== undefined) { if(table[position].key === key) { table[position] = undefined return true } else { let index = ++position // If the key exists and the key of the key is the current key, the system will pop up. while(table[index] === undefined || table[index].key !== key) { index++ } if(table[index].key === key) { table[index] = undefined return true } } } return false } this.get = function(key) { let position = loseloseHashCode[key] if(table[position] !== undefined) { if(table[position].key === key) { return table[position].value } else { let index = ++position // If the key exists and the key of the key is the current key, the system will pop up. while(table[index] === undefined || table[index].key !== key) { index++ } if(table[index].key === key) { return table[index].value } } } return undefined } this.print = function(key) { console.dir(table) let tables = table.filter(item=>item) console.log(tables) for (let i = 0; i < tables.length; i++) { console.log(`$-$`) } } } // Key Conflict var hash = new HashTable(); hash.put('Gandalf', '[email protected]'); hash.put('John', '[email protected]'); hash.put('Tyrion', '[email protected]'); hash.put('Aaron', '[email protected]'); hash.put('Donnie', '[email protected]'); hash.put('Ana', '[email protected]'); hash.put('Jonathan', '[email protected]'); hash.put('Jamie', '[email protected]'); hash.put('Sue', '[email protected]'); hash.put('Mindy', '[email protected]'); hash.put('Paul', '[email protected]'); hash.put('Nathan', '[email protected]'); hash.print()Djb2 (recommended by the community)
function HashTable() { let table = [] let djb2HashCode = function(key) { let hash = 5318 // Including initializing a hash variable and assigning it to a prime number for (let i = 0; i < key.length; i++) { hash += hash * 33 + key.charCodeAt(i) // hash * 33 (used as a magic number) } return hash % 1013 // The remainder of the division of another random prime number (larger than we think the hash table is - in this case, we think the hash table is 1000) } this.put = function(key, value) { let position = djb2HashCode(key) console.log(position + '-' + key) console.log(position) table[position] = value } this.remove = function(key) { table[djb2HashCode(key)] = undefined } this.get = function(key) { return table[djb2HashCode(key)] } this.getTable = function(key) { return table } } // Key Conflict var hash = new HashTable(); hash.put('Gandalf', '[email protected]'); hash.put('John', '[email protected]'); hash.put('Tyrion', '[email protected]'); hash.put('Aaron', '[email protected]'); hash.put('Donnie', '[email protected]'); hash.put('Ana', '[email protected]'); hash.put('Jonathan', '[email protected]'); hash.put('Jamie', '[email protected]'); hash.put('Sue', '[email protected]'); hash.put('Mindy', '[email protected]'); hash.put('Paul', '[email protected]'); hash.put('Nathan', '[email protected]'); console.dir(hash.getTable());