数据结构之散列表(三)

327 阅读2分钟

这是我参与更文挑战的第23天,活动详情查看:更文挑战

冲突解决

1. 书写更好的散列函数

既然我们知道了冲突是由于在创建之初由于散列函数给出了相同的hash导致的,那么根源的上的解决办法就是重写一个更好的不会返回重复hash值的散列函数,从而避免冲突。

而一个表现良好的散列函数是由几个方面构成的:插入和检索元素的时间(即性能),也包括较低的冲突的可能性。 举个🌰:

let dib2HashCode = function (key) {
    // 初始化hash变量值为5381
    let hash = 5381
    // 迭代参数key,将hash乘以33并和当前迭代到的字符的ASCII码值相加
    for(let i = 0; i < key.length; i++) {
        hash = hash * 33 + key.charCodeAt(i)
    }
    // 最后取余
    return hash % 1013
}

2. 线性探查 线性探查就是:当想向散列表中的某个位置加入一个新元素的时候,如果索引为index的位置已经被占据了,就尝试index+1位置,如果index+1的位置也被占据了那么就尝试idnex+2的位置,以此类推。

简单来说就是从index位置开始挨个试,一个不行就换下一个,直到找到空余的位置。

看代码:

function HashTable () {
    let table = []
    
    let loseloseHashCode = function (key) {
        let hash = 0
        // 使用组成key的每个字符的ASCII码值
        for (let i = 0; i < key.length; i++) {
            hash += key.charCodeAt(i)
        }
        return hash % 37
    }
    // 辅助类
    let ValuePair = function (key, value) {
        this.key = key
        this.value = value
    }
    
    this.put = function (key, value) {
        let position = loseloseHashCode(key)
        if (!table[position]) {
            table[position] = new ValuePair(key, value)
        } else {
            // 此处position位置已有元素占据,那么直接从positon+1位置处开始遍历查找
            let index = ++position
            while (table[index]) {
                // 迭代index
                index++
            }
            // 循环体外说明该index位置是undefined意味着可以存放新值
            table[index] = new ValuePair(key, value)
        }
    }
    
    this.get = function (key) {
        let position = loseloseHashCode(key)
        if(table[position]) {
            if (table[position].key === key) {
                return table[position].value
            } else {
                let index = ++position
                while (table[index] && table[index]?.key !== key) {
                    index++
                }
                if(table[index] && table[index]?.key === key) {
                    return table[index].value
                }
            }
            
        }
        return undefined
    }
    
    this.remove = function (key) {
        let position = loseloseHashCode(key)
        if(table[position]) {
            if (table[position].key === key) {
                 table[position] = undefined
            } else {
                let index = ++position
                while (table[index] && table[index]?.key !== key) {
                    index++
                }
                if(table[index] && table[index]?.key === key) {
                    table[index] = undefined
                }
            }
        }
        return false
    } 
}

至此,我们已经有三种方式解决散列表的冲突了:

  • 分离链接
  • 线性探查
  • 创建更好的散列函数