散列
散列使用的数据结构叫做散列表,在散列表上插入,删除,取用数据非常快
散列概述
所有元素根据该元素的键,保存在对应的位置,该键和字典的键是类似的概念 使用散列表存储数据时,通过一个散列函数将键映射到一个数字,这个数字的范围是0到这个散列表的长度
理想情况下,散列函数将会把每个键映射到唯一个数组索引,然后键的数量是无限的 一个更现实的目标是让散列函数尽量将键均匀的映射在数组中
hashTable 类
function HashTable() {
this.table = new Array(137)
}
HashTable.prototype = {
// 下面的散列函数是一种简易的计算函数,非常有可能导致不同的data输出相同的结果
// 如果发生这种情况就会影响后续的存储操作
simpleHash: function(data) {
var total = 0
for(var i = 0; i< data.length; i++) {
total += data.charCodeAt(i)
}
console.log(`hash: ${total}`, data)
return total % this.table.length
},
put: function(data) {
var pos = this.simpleHash(data)
this.table[pos] = data
},
showDistro: function(){
var arr = []
for (let i = 0; i < this.table.length; i++) {
if(this.table[i] != undefined) {
arr[i] = this.table[i]
}
}
console.log(arr)
return arr
}
}
var someName = ['David','Jennifer','Donnie','Raymond','Mike','Danny','Jonathan','Clayton']
// Raymond Clayton 的hash值是一样的 结果导致 Raymond被覆盖
var hTable = new HashTable()
for(var i=0; i< someName.length; i++) {
hTable.put(someName[i])
}
hTable.showDistro()
更好的散列函数
上面的例子说明我们需要一个更好的散列函数才能防止意外发生
- 霍纳算法
betterHash: function(string, arr) {
const H = 37
var total = 0
for(var i=0; i< string.length; i++) {
total += H * total + string.charCodeAt(i)
}
total = total % arr.length
return parseInt(total)
},
对散列表排序,从列表取值
put: function (key, data) {
// var pos = this.simpleHash(data)
var pos = this.betterHash(key)
console.log('pos', pos)
this.table[pos] = data
},
get: function (key) {
return this.table[this.betterHash(key)]
},
var pnumbers = new HashTable()
pnumbers.put('GUOHUA', '15045814518')
pnumbers.put('TABLE', '15648149784')
pnumbers.put('LOAWDF', '15297856666')
pnumbers.showDistro()
pnumbers.get('GUOHUA') // 15045814518
碰撞处理
- 开链法
在创建存储散列过的键值的数组时,通过调用一个新的空数组,这样就创建了一个二维数组,我们称之为链
table的每一项都成为一个数组,在put时把key值相同的值都push到数组中,就不会丢失数据了
function HashTable() { this.table = new Array(137) } HashTable.prototype = { buildChains: function() { for(var i = 0; i< this.table.length; i++) { this.table[i] = new Array() } }, // 下面的散列函数是一种简易的计算函数,非常有可能导致不同的data输出相同的结果 // 如果发生这种情况就会影响后续的存储操作 simpleHash: function (data) { var total = 0 for (var i = 0; i < data.length; i++) { total += data.charCodeAt(i) } console.log(`hash: ${total}`, data) return total % this.table.length }, betterHash: function (string) { const H = 37 var total = 0 for (var i = 0; i < string.length; i++) { total += H * total + string.charCodeAt(i) } total = total % this.table.length if(total<0) { total += this.table.length - 1 } return parseInt(total) }, // put 键值对 key -- data put: function (key, data) { // var pos = this.simpleHash(data) var pos = this.betterHash(key) this.table[pos].push([key, data+'123']) }, get: function (key) { let index = this.table[this.betterHash(key)].indexOf(key) return this.table[this.betterHash(key)][index+1][1] }, showDistro: function () { var arr = [] for (let i = 0; i < this.table.length; i++) { if (this.table[i] != undefined) { arr[i] = this.table[i] } } console.log(arr) return arr } } var someName = ['David', 'Jennifer', 'Donnie', 'Raymond', 'Mike', 'Danny', 'Jonathan', 'Clayton','Raymond'] // Raymond Clayton 的hash值是一样的 结果导致 Raymond被覆盖 var hTable = new HashTable() hTable.buildChains() for (var i = 0; i < someName.length; i++) { hTable.put(someName[i], someName[i]) } hTable.showDistro() - 线性探测法
在处理一个碰撞时,判断它的下一个位置是否是空,如果是空,把数组存在这个位置,如果不是空,就判断下下一个位置,直到找到一个空的位置。
/* 线性探测*/ // function put(key, data) { // var pos = this.betterHash(key) // if(this.table[pos] == undefined) { // this.table[pos] = key // this.value[pos] = data // } else { // while(this.table[pos] != undefined) { // pos ++ // } // this.table[pos] = key // this.value[pos] = data // } // }; // function get(key) { // var hash = -1 // hash = this.betterHash(key) // if(hash > -1) { // for(var i = hash; this.table[hash] != undefined; i++) { // if(this.table[hash] == key) { // return this.values[hash] // } // } // } // return undefined // }0
完整代码
// function HashTable() {
// this.table = new Array(137)
// }
// HashTable.prototype = {
// // 下面的散列函数是一种简易的计算函数,非常有可能导致不同的data输出相同的结果
// // 如果发生这种情况就会影响后续的存储操作
// simpleHash: function (data) {
// var total = 0
// for (var i = 0; i < data.length; i++) {
// total += data.charCodeAt(i)
// }
// console.log(`hash: ${total}`, data)
// return total % this.table.length
// },
// betterHash: function (string) {
// const H = 37
// var total = 0
// for (var i = 0; i < string.length; i++) {
// total += H * total + string.charCodeAt(i)
// }
// total = total % this.table.length
// if(total<0) {
// total += this.table.length - 1
// }
// return parseInt(total)
// },
// // put 键值对 key -- data
// put: function (key, data) {
// // var pos = this.simpleHash(data)
// var pos = this.betterHash(key)
// this.table[pos] = data
// },
// get: function (key) {
// return this.table[this.betterHash(key)]
// },
// showDistro: function () {
// var arr = []
// for (let i = 0; i < this.table.length; i++) {
// if (this.table[i] != undefined) {
// arr[i] = this.table[i]
// }
// }
// console.log(arr)
// return arr
// }
// }
// var someName = ['David', 'Jennifer', 'Donnie', 'Raymond', 'Mike', 'Danny', 'Jonathan', 'Clayton']
// // Raymond Clayton 的hash值是一样的 结果导致 Raymond被覆盖
// var hTable = new HashTable()
// for (var i = 0; i < someName.length; i++) {
// hTable.put(someName[i], someName[i])
// }
// hTable.showDistro()
// var pnumbers = new HashTable()
// pnumbers.put('GUOHUA', '15045814518')
// pnumbers.put('TABLE', '15648149784')
// pnumbers.put('LOAWDF', '15297856666')
// pnumbers.showDistro()
// pnumbers.get('GUOHUA') // 15045814518
/*
开链法处理碰撞
*/
function HashTable() {
this.table = new Array(137)
}
HashTable.prototype = {
buildChains: function() {
for(var i = 0; i< this.table.length; i++) {
this.table[i] = new Array()
}
},
// 下面的散列函数是一种简易的计算函数,非常有可能导致不同的data输出相同的结果
// 如果发生这种情况就会影响后续的存储操作
simpleHash: function (data) {
var total = 0
for (var i = 0; i < data.length; i++) {
total += data.charCodeAt(i)
}
console.log(`hash: ${total}`, data)
return total % this.table.length
},
betterHash: function (string) {
const H = 37
var total = 0
for (var i = 0; i < string.length; i++) {
total += H * total + string.charCodeAt(i)
}
total = total % this.table.length
if(total<0) {
total += this.table.length - 1
}
return parseInt(total)
},
// put 键值对 key -- data
put: function (key, data) {
// var pos = this.simpleHash(data)
var pos = this.betterHash(key)
this.table[pos].push([key, data+'123'])
},
get: function (key) {
let index = this.table[this.betterHash(key)].indexOf(key)
return this.table[this.betterHash(key)][index+1][1]
},
showDistro: function () {
var arr = []
for (let i = 0; i < this.table.length; i++) {
if (this.table[i] != undefined) {
arr[i] = this.table[i]
}
}
console.log(arr)
return arr
}
}
var someName = ['David', 'Jennifer', 'Donnie', 'Raymond', 'Mike', 'Danny', 'Jonathan', 'Clayton','Raymond']
// Raymond Clayton 的hash值是一样的 结果导致 Raymond被覆盖
var hTable = new HashTable()
hTable.buildChains()
for (var i = 0; i < someName.length; i++) {
hTable.put(someName[i], someName[i])
}
hTable.showDistro()
/* 线性探测*/
// function put(key, data) {
// var pos = this.betterHash(key)
// if(this.table[pos] == undefined) {
// this.table[pos] = key
// this.value[pos] = data
// } else {
// while(this.table[pos] != undefined) {
// pos ++
// }
// this.table[pos] = key
// this.value[pos] = data
// }
// };
// function get(key) {
// var hash = -1
// hash = this.betterHash(key)
// if(hash > -1) {
// for(var i = hash; this.table[hash] != undefined; i++) {
// if(this.table[hash] == key) {
// return this.values[hash]
// }
// }
// }
// return undefined
// }