22.哈希表

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

案例:

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

  1. 不使用數據庫,速度越快越好=>哈希表(散列)
  2. 添加時,保證按照 id 從低到高插入
  3. 使用鏈表來實現哈希表, 該鏈表不帶表頭[即: 鏈表的第一個結點就存放僱員信息]
  4. 思路分析並畫出示意圖
    在這裏插入圖片描述
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;
	}
	
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章