(數據結構和算法)哈希表的講解和案例實現

哈希表

一般的數據實現

看一個實際需求,google公司的一個上機題:

有一個公司,當有新的員工來報道時,要求將該員工的信息加入(id,性別,年齡,住址…),當輸入該員工的id時,要求查找到該員工的 所有信息.

要求: 不使用數據庫,儘量節省內存,速度越快越好=>哈希表(散列)

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

散列表,哈希表

實現詳解

  • 上述圖例爲韓順平老師所制。

  • 題目分析:題目要求其實就是實現對象的增刪改查,無論你是用queue還是鏈表都是可以實現的,但是此處要求就是越快越好,面試的情況下這種題目說最簡單的當然不是最優解,那麼哈希表(散列表)就能在鏈表的基礎上更加提升性能,減少了遍歷的時間,數據量越大分的鏈表越多那麼相對減少的時間是十分可觀的。

  • 實現:一個數組中放多個鏈表,放入哪個由id的hash得到,此處用取模得到位置。

  • 過程:員工對象 -> 鏈表 -> hash表 -> 實現

  • 鏈表類

class LinkedListEmp{

    private Emp head;//頭結點,每個鏈表需要頭結點來定位
    //添加員工
    public void add(Emp nemp){
        if (head == null){//爲空直接添加
            head = nemp;
            return;
        }
        Emp temp = head;//一個臨時變量
        while (true){
            if (temp.next==null){//成立時說明遍歷到鏈表最後了
                break;
            }
            temp = temp.next;//沒到最後就一直向後遍歷
        }
        temp.next = nemp;//新員工添加到最後
    }

    //展示所有的員工
    public void show(int n){
        if (head == null){
            System.out.println("鏈表"+(n+1)+"爲空;");
            return;
        }
        Emp temp = head;
        System.out.print("鏈表"+(n+1)+":");
        while (true){
            System.out.printf("->> %d :%s\t" , temp.id , temp.name);
            if (temp.next == null){
                break;
            }
            temp=temp.next;
        }
        System.out.println();
    }

    //根據id找員工
    public Emp findEmpByID(int id){
        if (head == null){
            System.out.println("此鏈表爲空!");
        }
        Emp temp = head;
        while (true){
            if (temp.id == id){//找到員工號就退出
                break;
            }
            temp = temp.next;
            if (temp.next==null){
                return null;//沒找到返回null
            }
        }
        return temp;//返回這個員工
    }

    public void deleteEmpById(int id){//刪除員工
        if (head == null){
            System.out.println("此鏈表爲空!");
        }
        Emp temp = head;
        while (true){//此處與普通單鏈表有區別,如果頭結點就是要找的員工,那麼直接換頭結點
            if (head.id == id){
                head = temp.next;
                System.out.println("刪除員工:"+id);
                break;
            }else if (temp.next.id == id){//如果找到將next域指向下下一個對象,那麼中間的對象就拋棄了,也就刪除了
                temp.next = temp.next.next;
                System.out.println("刪除員工:"+id);
                break;
            }
            if (temp.next == null){
                System.out.println("沒有找到此員工!!");
                break;
            }
            temp = temp.next;
        }
    }
}
  • 員工類
//員工類
class Emp{
    int id;
    String name ;
    Emp next = null;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
  • 哈希表
//哈希表
class HashEmpTable{
    int size;
    LinkedListEmp[] hashEmpTable;//定義一個以鏈表爲數據類型的數組

    public HashEmpTable(int size) {//初始化數組和確認空間大小
        this.size=size;
        hashEmpTable = new LinkedListEmp[size];
        for (int i = 0; i < size; i++) {
            hashEmpTable[i] = new LinkedListEmp();
        }
    }
    //添加
    public void add(Emp emp){//直接利用方法取到這個id號的員工所在的鏈表,用那個鏈表調用。
        int funId = hashFunId(emp.id);
        hashEmpTable[funId].add(emp);
    }
    
    //展示
    public void show(){
        for (int i = 0; i < size; i++) {
            hashEmpTable[i].show(i);
        }
    }
    //刪除
    public void deleteEmpById(int id){//同樣,找到鏈表再刪除對象
        int funId = hashFunId(id);
        hashEmpTable[funId].deleteEmpById(id);
    }
    
    //find員工,
    public void findEmpById(int id){
        int funId = hashFunId(id);
        Emp emp = hashEmpTable[funId].findEmpByID(id);
        if (emp != null){
            System.out.printf("在第 %d 條鏈表找到員工-> %d,姓名是-> %s" , funId , emp.id , emp.name);
        }
    }
    
    //利用取模實現哈希尋找鏈表號
    public int hashFunId(int id){
        int hashId = id % size;
        return hashId;
    }

}

//員工類
class Emp{
    int id;
    String name ;
    Emp next = null;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
  • 實現類
public class HashExercise {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        HashEmpTable hashEmpTable = new HashEmpTable(7);
        String oper = "";
        while (true){
            System.out.println("add");
            System.out.println("show");
            System.out.println("find");
            System.out.println("delete");
            System.out.println("exit");
            oper = sc.next();
            switch (oper){
                case "add":
                    System.out.println("請輸入員工id");
                    int id = sc.nextInt();
                    System.out.println("請輸入員工姓名");
                    String name = sc.next();
                    Emp emp = new Emp(id, name);
                    hashEmpTable.add(emp);
                    break;
                case "show":
                    hashEmpTable.show();
                    break;
                case "find":
                    System.out.println("請輸入需要查找的員工ID");
                    int findId = sc.nextInt();
                    hashEmpTable.findEmpById(findId);
                    break;
                case "delete":
                    System.out.println("請輸入需要刪除的員工ID");
                    int deleteID = sc.nextInt();
                    hashEmpTable.deleteEmpById(deleteID);
                    break;
                case "exit":
                    return;
            }
        }
    }
}

將此例結合會建立對hash表的一個很好的入門思想。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章