8.散列

344 阅读1分钟

散列

散列使用的数据结构叫做散列表,在散列表上插入,删除,取用数据非常快

散列概述

所有元素根据该元素的键,保存在对应的位置,该键和字典的键是类似的概念 使用散列表存储数据时,通过一个散列函数将键映射到一个数字,这个数字的范围是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
    // }