演算法--查詢演算法
符號表
定義:符號表是一種儲存鍵值對的資料結構,支援兩種操作:插入(put),即將一組新的鍵值對存入表中;查好(get),即根據給定的鍵得到相應的值。
目的:符號表最主要的目的就是將一個鍵和一個值聯絡起來。用例能夠將一個鍵值對插入符號表並希望在之後能夠從符號表的所有鍵值對中按照鍵直接找到對應的值。
符號表是一種典型的抽象資料型別:它代表著一組定義清晰的值以及相應的操作,使得我們能夠將型別的實現和使用區分開來。
順序查詢
在查詢中我們一個一個地順序遍歷符號表中的所有鍵並使用equals()方法來尋找與被查詢的鍵匹配的鍵。
演算法:順序查詢(基於無序連結串列)
public class SequenialSearchST<Key,Value>{
pirvate Node first;
pirvate class Node{
Key key;
Value val;
Node next;
public Node(Key key,Value val,Node next){
this.key = key;
this.val = val;
this .next = next;
}
}
//查詢給定的鍵,返回相關聯的值
public Value get(Key key){
for(Node x = first; x != null ; x = x.next){
if(key.equals(x.key)){
return x.val;
}
}
return null;
}
//查詢給定的鍵,找到則更新其值,否則在表中新建結點
public void put(){
for(Node x = firstl ; x != null ; x= x.next){
if(key.equals(x.key)){
x.val = val;
return;
}
}
first = new Node(key,val,first);
}
}
命題:在含有N對鍵值的基於(無序)連結串列的符號表中,未命中的查詢和插入操作都需要N次比較。命中的查詢在最壞情況下需要N次比較。特別地,向一個空表中插入N個不同的鍵需要~N^2/2次比較。
證明:在表中查詢一個不存在的鍵時,我們會將表中的每個鍵和給定的鍵比較。因為不允許出現重複的鍵,每次插入操作之前我們都需要這樣查詢一遍。
推論:向一個空表中插入N個不同的鍵需要~N^2/2次比較。
查詢一個已經存在的鍵並不需要線性級別的時間。一種度量方法是查詢表中的每個鍵,並將總時間除以N。在查詢中的每個鍵的可能性都相同的情況下時,這個結果就是依稀查詢平均所有的比較數。我們將它稱為隨機命中。
有序陣列中的二分查詢
演算法:二分查詢(基於有序陣列)
public class BinarySearchST<Key extends Comparable<Key>,Value>{
private Key[] keys;
private Value[] vals;
private int N;
public BinarySearchST(int capacity){
key = (Key[]) new Comparable[capacity];
vals = (Value[]) new Object[capacity];
}
public int size(){
return N;
}
public Value get(Key key){
if(isEmpty()) return null;
int i = rank(key);
if(i < N && keys[i].compare(key) == 0){
return vals[i];
}else{
return null;
}
}
publice int rank(Key key){
}
//查詢鍵,找到則更新值,否則建立新的元素
public void put(Key key, Value val){
int i = rank(key);
if(i < N && keys[i].compare(key) == 0){
vals[i] = val;
return;
}
for(int j = N; j > i ; j--){
keys[j] = keys[j-1];
vals[j] = vals[j-1];
keys[i] = key;
vals[i] = val;
N++;
}
}
publice void delete(Key key){
}
}
在查詢時,我們先將被查詢的鍵和子陣列的中間鍵比較。如果被查詢的鍵小於中間鍵,我們就在左子陣列中繼續查詢,如果大於我們就在右子陣列中繼續查詢,否則中間鍵就是我們要找的鍵。
遞迴的二分查詢
public int rank(Key key,int lo,int hi){
if(hi <lo){
return lo;
}
int mid = lo + (hi - lo)/2;
int cmp = key.compareTo(keys[mid]);
if(cmp < 0){
return rank(key,lo,mid-1);
}else if(cmp >0){
return rank(key,mid+1,hi)
}else{
return mid;
}
}
演算法: 基於有序陣列的二分查詢(迭代)
public int rank(Key key){
int lo = 0;
int hi = N-1;
while(lo <= hi){
int mid = lo + (hi - lo)/2;
int cmp = key.compareTo(keys[mid]);
if(cmp < 0){
hi = mid -1;
}else if(cmp >0){
lo = mid +1;
}else {
return mid;
}
}
return lo;
}
使用的資料結構 | 實現 | 有點 | 缺點
————–|——|——|—-
連結串列()| SequentialSearchST| 適用於小型問題|對大型符號表很慢
二叉查詢樹
我們所使用的資料結構由結點組成,結點包含的連結可以指向空(null)或者其他結點。在二叉樹中,每個結點只能有一個父結點指向自己(根結點沒有父結點),而且每個結點都只有在左右兩個連結,分別指向自己的左子結點,和右子結點。
定義:一顆二叉查詢樹是一顆二叉樹,其中每個結點都包含有一個Comparable的鍵(以及相關聯的值)且每個結點的鍵都大於其左子樹中的任意結點的鍵而小於右子樹的任意結點鍵。