雜湊表的程式碼實現(Java)

青冥夜雨寒風吹發表於2020-12-03

雜湊表介紹

雜湊表(Hash table,也叫雜湊表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做雜湊表。如下圖所示:

雜湊表一般由:1)陣列+連結串列;2)陣列+二叉樹構成。

以google公司的一個上機題為例建立雜湊表:

看一個實際需求,google公司的一個上機題: 
有一個公司,當有新的員工來報導時,要求將該員工的資訊加入(id,性別,年齡,住址..),當輸入該員工的id時,要求查詢到該員工的 所有資訊.
要求: 不使用資料庫,儘量節省記憶體,速度越快越好=>雜湊表(雜湊)

新增時,保證按照id從低到高插入 
使用連結串列來實現雜湊表, 該連結串列不帶表頭[即: 連結串列的第一個結點就存放僱員資訊] 

程式碼實現:

import java.util.Scanner;

public class HashTabDemo {

	public static void main(String[] args) {
		
		//建立雜湊表
		HashTab hashTab = new HashTab(7);
		
		//寫一個簡單的選單
		String key = "";
		Scanner scanner = new Scanner(System.in);
		while(true) {
			System.out.println("add:  新增僱員");
			System.out.println("list: 顯示僱員");
			System.out.println("find: 查詢僱員");
			System.out.println("exit: 退出系統");
			
			key = scanner.next();
			switch (key) {
			case "add":
				System.out.println("輸入id");
				int id = scanner.nextInt();
				System.out.println("輸入名字");
				String name = scanner.next();
				//建立 僱員
				Emp emp = new Emp(id, name);
				hashTab.add(emp);
				break;
			case "list":
				hashTab.list();
				break;
			case "find":
				System.out.println("請輸入要查詢的id");
				id = scanner.nextInt();
				hashTab.findEmpById(id);
				break;
			case "exit":
				scanner.close();
				System.exit(0);
			default:
				break;
			}
		}		
	}

}

//建立HashTab 管理多條連結串列
class HashTab {
	private EmpLinkedList[] empLinkedListArray;
	private int size; //表示有多少條連結串列
	
	//構造器
	public HashTab(int size) {
		this.size = size;
		//初始化empLinkedListArray
		empLinkedListArray = new EmpLinkedList[size];
		//?留一個坑, 這時不要分別初始化每個連結串列
		for(int i = 0; i < size; i++) {
			empLinkedListArray[i] = new EmpLinkedList();
		}
	}
	
	//新增僱員
	public void add(Emp emp) {
		//根據員工的id ,得到該員工應當新增到哪條連結串列
		int empLinkedListNO = hashFun(emp.id);
		//將emp 新增到對應的連結串列中
		empLinkedListArray[empLinkedListNO].add(emp);
		
	}
	//遍歷所有的連結串列,遍歷hashtab
	public void list() {
		for(int i = 0; i < size; i++) {
			empLinkedListArray[i].list(i);
		}
	}
	
	//根據輸入的id,查詢僱員
	public void findEmpById(int id) {
		//使用雜湊函式確定到哪條連結串列查詢
		int empLinkedListNO = hashFun(id);
		Emp emp = empLinkedListArray[empLinkedListNO].findEmpById(id);
		if(emp != null) {//找到
			System.out.printf("在第%d條連結串列中找到 僱員 id = %d\n", (empLinkedListNO + 1), id);
		}else{
			System.out.println("在雜湊表中,沒有找到該僱員~");
		}
	}
	
	//編寫雜湊函式, 使用一個簡單取模法
	public int hashFun(int id) {
		return id % size;
	}
	
	
}

//表示一個僱員
class Emp {
	public int id;
	public String name;
	public Emp next; //next 預設為 null
	public Emp(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
}

//建立EmpLinkedList ,表示連結串列
class EmpLinkedList {
	//頭指標,執行第一個Emp,因此我們這個連結串列的head 是直接指向第一個Emp
	private Emp head; //預設null
	
	//新增僱員到連結串列
	//說明
	//1. 假定,當新增僱員時,id 是自增長,即id的分配總是從小到大
	//   因此我們將該僱員直接加入到本連結串列的最後即可
	public void add(Emp emp) {
		//如果是新增第一個僱員
		if(head == null) {
			head = emp;
			return;
		}
		//如果不是第一個僱員,則使用一個輔助的指標,幫助定位到最後
		Emp curEmp = head;
		while(true) {
			if(curEmp.next == null) {//說明到連結串列最後
				break;
			}
			curEmp = curEmp.next; //後移
		}
		//退出時直接將emp 加入連結串列
		curEmp.next = emp;
	}
	
	//遍歷連結串列的僱員資訊
	public void list(int no) {
		if(head == null) { //說明連結串列為空
			System.out.println("第 "+(no+1)+" 連結串列為空");
			return;
		}
		System.out.print("第 "+(no+1)+" 連結串列的資訊為");
		Emp curEmp = head; //輔助指標
		while(true) {
			System.out.printf(" => id=%d name=%s\t", curEmp.id, curEmp.name);
			if(curEmp.next == null) {//說明curEmp已經是最後結點
				break;
			}
			curEmp = curEmp.next; //後移,遍歷
		}
		System.out.println();
	}
	
	//根據id查詢僱員
	//如果查詢到,就返回Emp, 如果沒有找到,就返回null
	public Emp findEmpById(int id) {
		//判斷連結串列是否為空
		if(head == null) {
			System.out.println("連結串列為空");
			return null;
		}
		//輔助指標
		Emp curEmp = head;
		while(true) {
			if(curEmp.id == id) {//找到
				break;//這時curEmp就指向要查詢的僱員
			}
			//退出
			if(curEmp.next == null) {//說明遍歷當前連結串列沒有找到該僱員
				curEmp = null;
				break;
			}
			curEmp = curEmp.next;//以後
		}		
		return curEmp;
	}
	
}

相關文章