6. 數據結構之哈希表--並自己實現哈希表

數據結構之哈希表

1. 哈希表的基本介紹

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

在這裏插入圖片描述

2. 需求分析

哈希表(散列)-Google 上機題

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

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

  • 使用鏈表來實現哈希表, 該鏈表不帶表頭[即: 鏈表的第一個結點就存放僱員信息]

在這裏插入圖片描述

3. 代碼實現

3.1 構建Emp

/**
 * 僱員類
 * 
 * @author DuanChaojie
 * @date 2020年3月12日 下午6:27:10
 * @version 1.0
 */
class Emp {

	public int id;// 員工id

	public String name;// 員工姓名

	public Emp next;// next默認爲null

	public Emp(int id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
}

3.2 創建EmpLinkedList表示鏈表


/**
 * 創建EmpLinkedList表示鏈表
 * 
 * @author DuanChaojie
 * @date 2020年3月12日 下午6:35:00
 * @version 1.0
 */
class EmpLinkedList {

	// 頭指針,執行第一個Emp,因此我們這個鏈表的head是直接指向第一個Emp
	private Emp head;// 默認爲null

	/*
	 * 添加僱員到鏈表 1. 假定,當添加僱員時,id 是自增長,即 id 的分配總是從小到大 因此我們將該僱員直接加入到本鏈表的最後即可
	 * 
	 * @param emp
	 */
	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.println("第" + (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;
	}

    
}

3.3 創建HashTab管理多條鏈表

/**
 * 創建HashTab管理多條鏈表
 * 
 * @author DuanChaojie
 * @date 2020年3月12日 下午6:26:16
 * @version 1.0
 */
class HashTab {

	private EmpLinkedList[] empLinkedListArray;

	private int size;

	/*
	 * 構造器
	 */
	public HashTab(int size) {
		super();
		this.size = size;
		// 初始化哈希槽
		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);

	}

	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("在哈希表中,沒有找到該僱員");
		}

	}

	/**
	 * 散列函數,使用一個簡單取模法
	 * JDK的散列表對其進行更優處理
	 * @param id
	 * @return
	 */
	public int hashFun(int id) {
		return id % size;
	}

}

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;
			}

		}

	}
}

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