在一個有序或無序的線性串列中,要尋找一筆資料通常要透過特定的搜尋資料與比對方式
,如果資料量很大,花費在搜尋上的時間成本也就隨之增大。
hashing是一種鍵值與陣列索引的對應,我們透過特定的hashing函式,將指定的鍵值經過
運算而得到一個hashing code,這個hashing code就當作是陣列的索引,資料就儲存在這個
索引的位置中。
要得到hashing code的運算方式有很多種,像是中間平方法、除法、摺疊法等等,無論是
哪種方式,都有可能在兩種不同鍵值,卻得到相同hashing code的情況,這個時候稱之為碰
撞(collision),解決碰撞的方式也有許多種,最簡單的就是直接往hashing code所指向的位置之下一格作線性探測,直到找到空間為止,另外還有就是使用鏈結串列,當碰撞發生
時,就將新的元素以鏈結的方式加在同一個位置的後面(這也是Java中的Hashtable類別所採取的方式),影響hashing效能的因性之後稱之為load factor,它的計算方式是hash table中的元素除以可容納的空間大小,load factor越接近1,表示hash table中的元素越多,發生碰撞的機率也就越大。
無論如何,製作一個hash table是相當麻煩的,然而Java的Hashtable類別可以讓您無需注意這些細節,在不發生碰撞的狀況下,使用hash table可以一次運算就找到所要的資料,
然而這並不是沒有代價,因為使用hash table就是一種以空間換取時間的方式,使用Hashtable會耗用較多的記憶體,因為要預先空出一個夠大的空間來當作hashing code的對應空間。
如果您想瞭解更多有關於hash table的細節,可以參考資料結構方面的書籍,我們接下來
直接使用一個範例來示範Hashtable類別的使用:
import java.util.*;
import java.io.*;
class Student {
private String number;
private String name;
private double score;
public Student(String number, String name, double score) {
this.number = number;
this.name = name;
this.score = score;
}
public String getNumber() {
return number;
}
public String getName() {
return name;
}
public double getScore() {
return score;
}
}
public class UseHashtable {
public static void main(String[] args) {
try {
OpHashtable();
}catch(IOException e) {
System.out.println(e.toString());
}
}
private static void OpHashtable() throws IOException {
Hashtable table = new Hashtable();
BufferedReader buf = new BufferedReader(
new InputStreamReader(System.in));
int select;
String number, name;
double score;
Object val;
Student student;
System.out.println("使用Hashtable類別");
while(true) {
System.out.println("(1) 加入學生資料");
System.out.println("(2) 查詢學生資料");
System.out.println("(3) 移除學生資料");
System.out.println("(4) 列出所有資料");
System.out.println("(5) 離開");
System.out.print("> ");
select = Integer.parseInt(buf.readLine());
switch(select) {
case 1:
System.out.print("學號: ");
number = buf.readLine();
System.out.print("姓名: ");
name = buf.readLine();
System.out.print("成績: ");
score = Double.parseDouble(buf.readLine());
student = new Student(number, name, score);
val = table.put(number, student);
if(val == null)
System.out.println("資料存入....");
else
System.out.println("資料取代....");
break;
case 2:
System.out.print("學號: ");
number = buf.readLine();
student = (Student) table.get(number);
if(student != null)
System.out.println("學號: " + student.getNumber() +
"姓名: " + student.getName() +
"成績: " + student.getScore());
else
System.out.println("查無此筆資料....");
break;
case 3:
System.out.print("學號: ");
number = buf.readLine();
val = table.remove(number);
if(val != null)
System.out.println("學生 " + number + " 資料移除");
else
System.out.println("查無此筆資料....");
break;
case 4:
Enumeration enum = table.elements();
while(enum.hasMoreElements()) {
student = (Student) enum.nextElement();
System.out.println("學號: " + student.getNumber() +
"姓名: " + student.getName() +
"成績: " + student.getScore());
}
break;
case 5:
default:
System.exit(0);
}
}
}
}
執行結果:
java UseHashtable
使用Hashtable類別
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 1
學號: B83503124
姓名: 米小狗
成績: 93.2
資料存入....
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 1
學號: B86550032
姓名: 毛小狗
成績: 94
資料存入....
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 2
學號: B83503124
學號: B83503124 姓名: 米小狗 成績: 93.2
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 4
學號: B86550032 姓名: 毛小狗 成績: 94.0
學號: B83503124 姓名: 米小狗 成績: 93.2
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 3
學號: Bee323
查無此筆資料....
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 3
學號: B86550032
學生 B86550032 資料移除
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 4
學號: B83503124 姓名: 米小狗 成績: 93.2
(1) 加入學生資料
(2) 查詢學生資料
(3) 移除學生資料
(4) 列出所有資料
(5) 離開
> 5
Hashtable類別的使用基本上是很簡單的,put()方法需要一個物件作為計算hashing code之用,而第二個參數是所要存入的物件,這兩個參數都必須給定,否則的話會發生NullPointerException例外,而如果之前同一位置已有物件,而在存入時所指定的鍵值相同時,則新物件會取代原位置的物件,而舊物件會被傳回,同樣的我們使用remove()方法時,也會傳回被移除的物件。
ref:
http://blog.yam.com/bluelanguage/article/8401664