資料結構學習筆記四(二分查詢)
阿新 • • 發佈:2019-01-06
一、什麼是二分查詢
二分查詢針對的是一個有序的資料集合,每次都通過更區間的中間元素做對比,將要查詢的區間縮小為原來的一半,直到找到要查詢的元素,或者區間被縮小為0。其時間複雜度為O(logn)。
二、二分查詢應用場景的侷限性
1.二分查詢依賴的是順序表結構(即陣列)
二分查詢需要按照下標來隨機訪問元素。二分查詢只能用在順序表來儲存的資料結構上,如果資料是通過其他資料結構儲存的,則無法使用二分查詢。
2.二分查詢針對的是有序資料
二分查詢要求資料時有序的。如果資料沒有序,可以先排序。如果我們針對的是一組靜態資料,沒有頻繁的插入,刪除,我們可以進行一次排序,多次二分查詢。這樣排序的成本就被分攤,二分查詢的邊際成本就會比較低。但是如果資料集合有頻繁的插入和刪除操作,要使用二分查詢,在每次二分查詢前都要先進行排序。針對珍重動態資料集合,維護有序的成本很高。
二分查詢只能用在插入,刪除不頻繁,一次排序多次查詢的場景中。針對動態變化的資料集合,二分查詢將不再適應。
3.資料量太小不適合二分查詢
如果要處理的資料量很小,完全沒有必要使用二分查詢,順序查詢就夠了。但是有一個例外,如果資料之間的比較操作比較耗時,不管資料量大小,都推薦使用二分查詢。(比如陣列中儲存的都是長度超過300的字串,如此長的兩個字串進行比較就非常耗時,此時使用二分查詢可以減少比較次數,提高效能)
4.資料量太大也不適合二分查詢
二分查詢需要依賴陣列這種資料結構,而陣列為了支援隨機訪問的特性,要求記憶體空間連續,對記憶體的要求比較苛刻。如果太大的資料用陣列儲存就比較吃力了(開闢不出連續空間),也就不能用二分查找了。
三、二分查詢的適用範圍
凡是用二分查詢能解決的,絕大部分我們更傾向於用散列表或者二叉查詢數。實際上,求“值等於給定值”的二分查詢確實不怎麼會被用到,二分查詢更適合用在“近似”查詢問題,在這類問題上,二分查詢的優勢明顯。而用其他資料結構,比如散列表、二叉樹就比較難實現了。
四、二叉樹的變種
1.查詢第一個值等於給定值的元素
//1.查詢第一個值等於給定值的元素
public int binarySearch1(int[] a,int n,int value){
int low=0;
int high=n-1;
while(low<=high){
int mid=low+((high-low)>>1);
if(a[mid]<value){
low=mid+1;
}else if(a[mid]>value){
high=mid-1;
}else{
if(mid==0 || a[mid-1]!=value) //如果mid==0,那它已經是陣列的第一個元素了,一定是我們要找的
return mid; //如果mid不等於0,a[mid-1]不等於value,那a[mid]就是我們要找的
else
high=mid-1;
}
}
return -1;
}
2.查詢最後一個值等於給定值的元素
//2.查詢最後一個值等於給定值的元素
public int binarySearch2(int[] a,int n,int value){
int low=0;
int high=n-1;
while(low<=high){
int mid=low+((high-low)>>1);
if(a[mid]<value){
low=mid+1;
}else if(a[mid]>value){
high=mid-1;
}else{
if(mid==n-1 || a[mid+1]!=value)
return mid;
else
low=mid+1;
}
}
return -1;
}
3.查詢第一個大於等於給定值的元素
//3.查詢第一個大於等於給定值的元素
public int binarySearch3(int[] a,int n,int value){
int low=0;
int high=n-1;
while(low<=high){
int mid=low+((high-low)>>1);
if(a[mid]>=value){
if(mid==0 || a[mid-1]<value)
return mid;
else
high=mid-1;
}else{
low=mid+1;
}
}
return -1;
}
4.查詢最後一個小於等於給定值的元素
//4.查詢最後一個小於等於給定值的元素
public int binarySearch4(int[] a,int n,int value){
int low=0;
int high=n-1;
while(low<=high){
int mid=low+((high-low)>>1);
if(a[mid]<=value){
if(mid==n-1 || a[mid+1]>value)
return mid;
else
low=mid+1;
}else{
high=mid-1;
}
}
return -1;
}