順序查找
順序查找
(Sequential Search),又稱為線性查找
。是最基本的查找技術,它的查找過程,從表中的第一個(或最后一個)記錄開始,逐個進行記錄關鍵字和給定值比較。若某個記錄的關鍵字和給定值相等,說明查找成功,如果直到最后一個(或第一個)記錄,沒有關鍵字與給定值相等,說明查找不成功。
//a為數組,n為查找的數組個數,key為要查找的關鍵字;
int Sequential_Search(int *a,int n,int key){
for (int i = 0; i <= n - 1 ; i++)
if (a[i] == key)
return i;
//沒找到返回-1
return -1;
}
折半查找
折半查找(Binary Search)技術,又稱二分查找。
前提條件是線性表中的記錄必須是關鍵碼有序的(通常從小到大有序),線性表必須采用順序存儲。
基本思想:
- 在有序表中,取中間記錄作為比較對象,若給定值與中間記錄的關鍵字相等則查找成功。
- 若給定值小于中間記錄關鍵字,則在中間記錄的左半區繼續查找。
- 若給定值大于中間記錄關鍵字,則在中間記錄的右半區繼續查找。
- 重復以上操作,直到查找成功,或者查找結束還未找到即查找失敗。
//假設數組a,已經是有序的(從小到大)
int Binary_Search(int *a,int n,int key){
int low,high,mid;
//定義最低下標為記錄首位
low = 0;
//定義最高下標為記錄末位
high = n - 1;
while (low <= high) {
//折半計算
mid = (low + high) /2;
if (key < a[mid]) {
//若key比a[mid] 小,則將最高下標調整到中位下標小一位;
high = mid-1;
}else if(key > a[mid]){
//若key比a[mid] 大,則將最低下標調整到中位下標大一位;
low = mid+1;
}else
//若相等則說明mid即為查找到的位置;
return mid;
}
return 0;
}
折半查找優化
折半查找公式為mid = (low + high) / 2 = low + 1/2 (high - low)
考慮將1/2進行改進,方案如下:
假設,a[11] = {0, 1, 16, 24, 35, 47, 59, 62, 73, 88, 99} , low = 0, high = 10, 則 a[0] = 0, a[10] = 99, 如果需要查找key = 16,按照常規折半查找需要進行4次才能找到結果,但是如果用新的共識,則
對2.616取整,則
mid = 2
,那么我們只需要進行2次就能找到結果。
我們稱優化后的方法為插值查找
(Interpolation Search),是根據查找的關鍵字key與查找表中的最大最小記錄的關鍵字比較后的查找方法,核心在于mid的計算公式關鍵部分:
//插值查找
int Interpolation_Search(int *a,int n,int key){
int low,high,mid;
low = 1;
high = n;
while (low <= high) {
//插值
mid = low+ (high-low)*(key-a[low])/(a[high]-a[low]);
if (key < a[mid]) {
//若key比a[mid]插值小,則將最高下標調整到插值下標小一位;
high = mid-1;
}else if(key > a[mid]){
//若key比a[mid]插值 大,則將最低下標調整到插值下標大一位;
low = mid+1;
}else
//若相等則說明mid即為查找到的位置;
return mid;
}
return 0;
}
斐波拉契查找
斐波拉契查找
(Fibonacci Search)是利用斐波拉契數列為查找的下標數組,而不是折半查找中根據搜索數組下標來查找,說白了就是利用斐波拉契數列來生成新的mid
。
例如下面F為斐波拉契數列,a為要查找的記錄數組,長度為10,low = 1, high = 10, 給定值key = 99,查找a中是否有99,返回相應的下標:
計算過程:
-
由于n = 10, key = 99,F[6] < n < F[7],得到k = 7, 因為F[7] = 13, 而a最大僅有a[10], 后面的a[11],a[12] 是為賦值的,為了避免之后的數值比對數組越界問題,需要將后續的2個元素賦值,a[11] = a[12] = 99。
-
此時mid = low + F[k - 1] - 1 = 1 + F[7 - 1] - 1 = 1 + 8 -1 = 8;
key > a[8] ---> 99 > 73;
low = mid + 1 = 8 + 1 = 9;
k = k - 2 = 7 - 2 = 5;
mid = low + F[k - 1] - 1 = 1 + F[5 - 1] - 1 = 9 + 3 - 1 = 11;
key = a[11] ---> 99 = 99;
mid >n , 11 > 10, 則返回n,返回10.
表示找到key= 99是在數組a中的位置是10的位置上。
key = 99是處在邊緣的值,我們可以假設key = 59,來看看在a數組中間的數值計算過程又是怎樣的?
計算過程:
n = 10, 同上面一樣,得到k = 7, F[7] = 13, 補齊后兩位數值為a[11] = a[12] = a[10] = 99;
-
mid = low + F[k - 1] - 1 = 1 + F[7 - 1] - 1=1 + 8 - 1 = 8;
key < a[8] ---> 59 < 73;
high = mid - 1 = 8 - 1 = 7;
k = k - 1 = 6;
-
mid = low + F[k - 1] = 1 + F[6 - 1] - 1 = 1 + 5 -1 = 5;
key > a[5] ---> 59 > 47;
low = mid + 1 = 5 + 1 = 6;
k = k - 2 = 4;
-
mid = low +F[k - 1] - 1 = 6 + F[4 - 1] - 1 = 7;
key < a[7] ---> 59 < 62
high = mid - 1 = 6;
k = k - 1 = 3;
mid = low + F[k - 1] - 1 = 6 + 1 - 1 = 6;
key = a[6];
mid < n ; 6 < 10, 返回 6;
找到key = 59在數組a中的位置為6。
結論:
斐波拉契查找就是利用mid = low + F[k -1] - 1 這個公式來計算出mid的所在位置。然后比較給定值與a[mid]的大小,然后繼續或結束。
int F[100]; /* 斐波那契數列 */
//初始化數列
F[0]=0;
F[1]=1;
for(i = 2;i < 100;i++)
{
F[i] = F[i-1] + F[i-2];
}
//計算過程
int Fibonacci_Search(int *a,int n,int key){
int low,high,mid,i,k;
//最低下標為記錄的首位;
low = 1;
//最高下標為記錄的末位;
high = n;
k = 0;
//1.計算n為斐波拉契數列的位置;
while (n > F[k]-1) {
k++;
}
//2.將數組a不滿的位置補全值;
for(i = n;i < F[k]-1;i++)
a[i] = a[n];
//3.
while (low <= high) {
//計算當前分隔的下標;
mid = low+F[k-1]-1;
if (key < a[mid]) {
//若查找的記錄小于當前分隔記錄;
//將最高下標調整到分隔下標mid-1處;
high = mid-1;
//斐波拉契數列下標減1位;
k = k-1;
}else if(key > a[mid]){
//若查找的記錄大于當前的分隔記錄;
//最低下標調整到分隔下標mid+1處
low = mid+1;
//斐波拉契數列下標減2位;
k = k-2;
}else{
if (mid <= n) {
//若相等則說明,mid即為查找的位置;
return mid;
}else
{
//若mid>n,說明是補全數值,返回n;
return n;
}
}
}
return 0;
}
總結
綜上幾種數據查找的方法,說白了就是對mid的計算公式的不同,從而達到不同的效率。