數據結構學習之哈希表篇(一)

什麼是哈希表?
哈希表(Hash table,也叫散列表),是根據關鍵碼值(Key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做哈希函數,存放記錄的數組叫做哈希表。

哈希表充分體現了算法設計領域的經典思想:用空間換時間。
哈希表是時間與空間之間的平衡。
哈希函數的設計也是很重要的。
“鍵”通過哈希函數得倒的“索引”分佈越均勻越好。

我們關注的“鍵"的類型,在轉化爲數組的索引時一般哈希函數的設計原則

整型
小範圍正整數直接使用
小範圍負整數進行偏移( -100~100—>0~200)
大整數的通常做法:取模,取模時要具體問題具體分析。一個簡單的解決辦法就是模一個素數(素數又稱質數。一個大於1的自然數,除了1和它自身外,不能被其他自然數整除的數叫做質數;否則稱爲合數)。一個很小的例子來說明爲什麼要模一個素數,而不是合數:
取餘合數4:

10%4 2
20%4 0
30%4 2
40%4 0
50%4 2

取餘素數7:

10%7 3
20%7 6
30%7 2
40%7 5
50%7 1

取模素數時”索引“更連續,哈希衝突更少。

浮點型
在計算機中,浮點型都是32位(float)或者64位(double)的二進制表示,被計算機解析成了浮點數。所以浮點數可以轉成整型來處理。

字符串
轉成整型處理
166 = 1 * 10 ^ 2 + 6 * 10 ^ 1 + 6 * 10 ^ 0
code = c * B ^ 3 + o * B ^ 2 + d * B ^ 1 + e * B ^ 0
hash(code) = (c * B ^ 3 + o * B ^ 2 + d * B ^ 1 + e * B ^ 0 ) % M
hash(code) = ((((c * B) + o) * B + d) * B + e ) % M
hash(code) = ((((c % M) * B + o) % M * B + d) % M * B + e ) % M
最後一個式子轉換爲代碼:

int hash = 0;
for(int i = 0; i < str.length(); i ++){
    hash = (hash * B + str.charAt(i)) % M
}

複合類型
依然可以轉爲整型類型。即像處理字符串一樣把複合類型的每一部分分開來處理。

當然,轉成整型處理,並不是唯一的方法,只是一般的通用方法。
但不管怎樣,在設計哈希函數時我們要遵循下面三個原則:

  1. 一致性:即a==b,則hash(a) == hash(b)
  2. 高效性:計算高效簡便
  3. 均勻性:哈希值均勻分佈

定義一個Student並重寫它的hashCode與equals方法:

/**
 * @author ymn
 * @version 1.0
 * @date 2020\6\5 0005 16:00
 */
public class Student {

    int grade;
    int cls;
    String firstName;
    String lastName;

    public Student(int grade, int cls, String firstName, String lastName) {
        this.grade = grade;
        this.cls = cls;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public int hashCode() {
        int B = 7;
        int hash =0;
        hash = hash * B + grade;
        hash = hash * B + cls;
        hash = hash * B + firstName.toLowerCase().hashCode();
        hash = hash * B + lastName.toLowerCase().hashCode();
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        //判斷當前對象與obj的引用是否相同
        if (this == obj){
            return true;
        }
        //o是否爲空
        if (obj == null){
            return false;
        }
        //是否是一個類,避免出現傳進來的類是Student子類的情況
        if (getClass() != obj.getClass()){
            return false;
        }
        Student another = (Student)obj;
        return this.cls == another.cls &&
               this.grade == another.grade &&
               this.firstName.toLowerCase().equals(another.firstName.toLowerCase()) &&
               this.lastName.toLowerCase().equals(another.lastName.toLowerCase());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章