数据结构与算法之哈希表
最后更新: 2022-08-29
阅读时间: 2
min
前言 哈希表是一种常用的数据结构,可以快速的插入和取用,但是查询数据效率低下。
实现 基于数组实现哈希表,数组的长度是预先设定的,有需要是增加。最常见的是将数组的长度设为一个质数
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 class HashTable { table = <any >[] constructor ( ) { this .table = Array .from({ length: 137 }) } hash(data: string ) { let total = 0 for (let index = 0 ; index < data.length; index++) { total += data.charCodeAt(index) } return total % this .table.length } betterHash(data: string ) { const H = 37 let total = 0 for (let index = 0 ; index < data.length; index++) { total += H * total + data.charCodeAt(index) } total = total % this .table.length if (total < 0 ) { total += this .table.length - 1 } return parseInt (total.toString()) } put(key: string , data: any ) { const pos = this .betterHash(key) this .table[pos] = data } get (key: string ) { return this .table[this .betterHash(key)] } show() { for (let index = 0 ; index < this .table.length; index++) { const item = this .table[index] if (item) { console .log(`${index} : ${item} ` ) } } } }
测试下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const hashTable = new HashTable()hashTable.put('David' , 'David' ) hashTable.put('Jennifer' , 'Jennifer' ) hashTable.put('Donnie' , 'Donnie' ) hashTable.put('Raymond' , 'Raymond' ) hashTable.put('Cynthia' , 'Cynthia' ) hashTable.put('Mike' , 'Mike' ) hashTable.put('Clayton' , 'Clayton' ) hashTable.put('Danny' , 'Danny' ) hashTable.put('Jonathan' , 'Jonathan' ) hashTable.show() console .log('Jonathan: ' , hashTable.get('Jonathan' ))
输出
1 2 3 4 5 6 7 8 9 12 : Jennifer22 : Raymond55 : Donnie58 : Clayton80 : Jonathan82 : Mike103 : Cynthia110 : DannyJonathan: Jonathan
碰撞处理 当哈希方法对于多个输入产生了相同的输出是就会出现碰撞,两种可以解决键的碰撞问题开链法以及线性探测法
开链法
开链法指的是在实现 hash 表的底层数组中,每个数组又是一个新的数据结构,比如另一个数组,这样即使有两个键 hash 后的值相同,依然被保存在同样的位置,但是他们在第二个数组中的位置是不同的。
要实现开链法,在创建存储键值的数组时,通过一个函数创建一个新的数组,然后将该数组赋值给 hash 表里的每一个元素,创建一个二维数组。
线性探测法
线性探测法指的是当发生碰撞时检查 hash 表里的下一个位置是否为空,如果为空就将数据存入该位置,如果不为空,则继续查找下一个位置,直到找到空位子为止。通常来说如果数组的大小是待存储数据个数的 1.5 倍时,那么用开链法;如果数组的大小是待存储的数据两倍以上时,那么使用线性探测法。