1. 程式人生 > >資料結構——排序與查詢(5)——折半查詢(C++實現)法

資料結構——排序與查詢(5)——折半查詢(C++實現)法

順序查詢

順序查詢,是一種最直觀的查詢方式。原理閒蕩簡單就是我們正常思維的查詢,從給定的序列出發,依次檢查序列中的每一個專案是否為我們給定的關鍵字。是則查詢成功,否則查詢失敗。

bool searchByOrder(vecter<int> vec){
	for(int i = 0; i < vec.size(); i++){
		if(vec[i] = k ) return true;
		return false;
	}
}

這段程式碼是現場寫的,應該都非常熟悉,如果有N個元素,那麼最壞的情況下我們需要O(n)的時間。因此也稱為線性查詢

而對於有序表

,我們則可以進行改進。有序表就是表中的資料已經排好序,我們只需要對其遍歷即可。考慮這樣一種情況:
我們要對一串數字進行查詢 10 20 30 40 50,給定的要查詢的key為 25。那麼我們至少要進行多少次比較呢?顯然是3次,依次是 10 20 30因為後面的數不用看都知道一定比25大(這是有序表),因此這樣我們遍歷的次數就可以減少一些。因為 20 < 25 <30,因此25只能存在20 和 30之間。而他們之間又沒有其他數,所以必定查詢失敗。如果查詢的是40,那麼我們就能在不遍歷50的情況下找到40

折半查詢法

但是對於有序表來講,有比上面更好的做法。我們稱為折半查詢法,也稱二分查詢(binary search)。這是一種典型的遞迴演算法。具體的思想和程式碼我就不說了。為什麼?在遞迴的部落格中就談到過:

C++抽象程式設計——遞迴簡介(5)——檢查迴文數,折半查詢
說說簡單的思想:我們在一個線性表中找一個數,最壞的情況是O(n),如果我們每次將尋找的區間縮小一半,也就相當於將搜尋的範圍縮小一半。那麼就大大提高了查詢的效率。貼個C++程式碼看看:

​
int findInSortedVector(string key, Vector<string> & vec) {
	return binarySearch(key, vec, 0, vec.size() - 1);//返回折半查詢的結果
}
int binarySearch(string key, Vector<string> & vec, int p1, int p2) {
	if (p1 > p2) return -1; //設定折半查詢的邊界從p1 到 p2
	int mid = (p1 + p2) / 2; //取中點(向上取整)劃分區間
	if (key == vec[mid]) return mid;//如果中間的值恰好等於要找的值,直接返回
	if (key < vec[mid]) { //否則,判斷給定的值在哪個區間內
		return binarySearch(key, vec, p1, mid - 1); //在此區間 ,遞迴呼叫折半查詢
	} else {
	return binarySearch(key, vec, mid + 1, p2);//在另一個區間呼叫折半查詢
	}
}

折半查詢與二叉搜尋樹

有沒有發現這個過程跟什麼有點像?沒錯,其實這就是二叉搜尋樹的構成原理。我們曾經舉過例子將一個無序的數字序列構建出一顆二叉搜尋樹。可以看看這裡:資料結構——樹(7)——二叉搜尋樹及其操作原理

因此,由折半查詢法找到給定的值,最壞的結果是把整個樹的高度走了一遍,即樹高h = log2^(n + 1)。因此最壞情況是O(log2^n);
但是尤其注意,由於折半查詢法要方便的定位查詢固定區域,因此其儲存結構必須符合隨機存取,即順序儲存結構且要求序列已經排好序