1. 程式人生 > 其它 >2、idea 啟動專案JDK、JRE報錯:Class JavaLaunchHelper ...One of the two will be used. Which one is undefined.

2、idea 啟動專案JDK、JRE報錯:Class JavaLaunchHelper ...One of the two will be used. Which one is undefined.

技術標籤:演算法與資料結構雜湊表連結串列資料結構java

一、雜湊表概述

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

其實把雜湊表看做是字典來理解雜湊表就很容易明白了,我們通過關鍵碼即可快速定位關鍵值。顯而易見雜湊表有一個很大的優點就是查詢資料的速度快

如下所示就是一個典型的雜湊表:

在這裡插入圖片描述

雜湊表是陣列和連結串列的結合體,上圖的雜湊表左邊是一個數組,右邊是連結串列,即陣列中的每個元素都是一個連結串列。一個新的結點具體新增到哪個連結串列中是由對映關係來決定的。同樣,我們如果想要查詢某個結點,只需要通對結點的關鍵碼進行對映關係運算,計算出在陣列的第幾個元素(即哪個連結串列),然後遍歷連結串列比對關鍵碼即可得出結果。

從典型的雜湊表結構中,我們可以得出這樣的結論:本質上雜湊表是一個元素為連結串列的陣列

二、雜湊表的程式碼實現

下面以 google 的一個上機題為例來做程式碼實現。

【案例描述】

有一個公司,當有新的員工來報道時,要求將該員工的資訊加入(id、名字、…),當輸入該員工的 id 時,要求查詢到該員工的所有資訊。要求不使用資料庫,速度越快越好。

【思路分析】

要求不使用資料庫,而且是通過員工 id 來查詢員工的所有資訊,很明顯可以使用雜湊表來解決。

在本例中,員工的 id 是關鍵碼,我們可以對員工的 id 取餘來作為到連結串列的對映。假設陣列的長度是 5,比如 id 取餘 5 等於 0 的員工都存放到第一個連結串列中(如 5、15…)、再比如 id 取餘5 等於 2 的都存放到第 3 個連結串列中(如 2、7、12…)。其實現程式碼如下:

// 模擬獲取雜湊值,該值決定結點要存放到陣列的第幾個連結串列
public int hashFun(int id){
    return id % size;
}

本案例中要實現一個雜湊表,需要三個類:一個類作為結點類存放僱員的個人資訊、一個類作為連結串列類,用於記錄相同餘數的僱員結點、一個類作為雜湊表類。通過雜湊表類可以實現對任意結點(也即員工)進行增刪改查,而增刪改查的具體操作也就是對結點的具體操作,則是要通過連結串列類來實現。

【程式碼實現】

本案例完整的雜湊表程式碼實現如下:

public class No1_HashTable {
    public static void main
(String[] args) { Scanner input = new Scanner(System.in); MyHashTable hashTable = new MyHashTable(6); // 建立雜湊表 while (true){ System.out.println(); System.out.println("(add)新增僱員"); System.out.println("(ser)查詢僱員"); System.out.println("(lis)顯示僱員"); System.out.println("(del)刪除僱員"); System.out.println("(ext)退出"); System.out.print("請輸入選項:"); String choice = input.nextLine(); switch (choice){ case "add": // 新增 System.out.print("請輸入ID:"); int id = Integer.parseInt(input.nextLine()); System.out.print("請輸入姓名:"); String name = input.nextLine(); hashTable.addEmp(new Employee(id, name)); break; case "ser": // 查詢 System.out.print("請輸入要查詢ID:"); hashTable.findById(Integer.parseInt(input.nextLine())); break; case "lis": // 顯示 hashTable.list(); break; case "del": // 刪除 System.out.print("請輸入要刪除ID:"); hashTable.deleteById(Integer.parseInt(input.nextLine())); break; case "ext": // 退出 break; default: System.out.println("輸入有誤!"); } } } } /** * 定義一個雜湊表 */ class MyHashTable{ private int size; private EmployeeLinkedList[] empList; public MyHashTable(int maxSize){ size = maxSize; empList = new EmployeeLinkedList[maxSize]; for (int i=0; i<maxSize; i++){ // 陣列中存放的不是基本型別時,必須初始化陣列 empList[i] = new EmployeeLinkedList(); } } // 新增一個結點到雜湊表中 public void addEmp(Employee emp){ int index = hashFun(emp.id); empList[index].addEmp(emp); } // 顯示所有結點 public void list(){ for (int i=0; i<size; i++){ System.out.printf("第 %d 個連結串列為:",i); empList[i].list(); System.out.println(); } } // 根據 id 查詢某個結點 public void findById(int id){ int index = hashFun(id); empList[index].findById(id); } // 根據 id 刪除某個結點 public void deleteById(int id){ int index = hashFun(id); empList[index].deleteById(id); } // 模擬獲取雜湊值,該值決定結點要存放到陣列的第幾個連結串列 public int hashFun(int id){ return id % size; } } /** * 定義一個僱員連結串列 */ class EmployeeLinkedList{ private Employee head = null; // 這裡的頭結點是有意義的,是一個真實的僱員 // 新增結點 public void addEmp(Employee employee){ if (head == null){ // 判斷連結串列是否為空 head = employee; return; } Employee cur = head; // 輔助指標 while(cur.next != null){ // 找到最後一個結點 cur = cur.next; } cur.next = employee; employee.next = null; } // 通過 id 查詢結點 public void findById(int id){ if (head == null){ // 判斷連結串列是否為空 System.out.printf("連結串列為空, ID 為 %d 的結點不存在!", id); return; } Employee cur = head; // 第一個結點不能動,要用輔助指標 while (cur != null){ if (cur.id == id){ System.out.printf("找到了!該結點資訊為:ID = %d,NAME = %s", id, head.name); return; } cur = cur.next; } System.out.println("該結點不存在!"); } // 通過 id 刪除結點 public void deleteById(int id){ if (head == null){ System.out.println("連結串列為空,無法刪除!"); return; } // 因為 head 結點也是一個有效結點,他沒有前驅,所以要單獨判斷 if (head.id == id){ // 如果第一個結點是目標結點 head = head.next; return; } // head 之後的節點都是有前驅結點的結點 Employee cur = head; // 輔助指標 while (true){ if (cur.next == null){ // 如果判斷到了最後一個結點還是沒有找到 System.out.println("該結點不存在!"); return; } if (cur.next.id == id){ cur.next = cur.next.next; return; } cur = cur.next; } } // 顯示所有結點 public void list(){ if (head == null){ System.out.print("連結串列為空!"); return; } Employee cur = head; // 輔助指標 while (cur != null){ System.out.printf(" =>ID:%d,NAME:%s", cur.id, cur.name); cur = cur.next; } } } /** * 定義一個僱員結點 */ class Employee{ public int id; public String name; public Employee next; public Employee(int id, String name){ this.id = id; this.name = name; } }