靜態查找表:只進行查找操作的查找表
動態查找表:在查找過程中同時插入查找表中不存在的元素,或者刪除已存在的元素
1.順序表查找:從第一個或者最後一個記錄開始,將每個記錄的關鍵字與給定值比較,若相等則查找成功。
C實現:
# include <stdio.h>
# include <stdlib.h>
int Sequential_Search(int *arr, int key, int n);
int main()
{
int a[5] = {2,3,5,8,7};
int index;
index = Sequential_Search2(a, 4, 5);
printf("順序查找的下標爲:%d \n", index);
system("pause");
return 0;
}
//順序查找
int Sequential_Search(int *arr, int key, int n)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == key)
{
return i;
}
}
}
//有哨兵順序查找
int Sequential_Search2(int *arr, int key, int n)
{
int i;
if (arr[0] == key)
return 0;
else
arr[0] = key; //設置a[0]爲關鍵字值,我們稱之爲“哨兵”
i = n; //循環從數組尾部開始
while (arr[i] != key)
{
i--;
}
if (0 == i)
{
printf("查找失敗\n");
return -1;
}
else
return i; //返回-1則說明查找失敗
}
時間複雜度:
最好情況:O(1),第一次就找到
最壞情況:O(n),需要逐個比較完
平均:O(n)
2.有序表查找:元素是有序排列的,且是順序存儲的(存在數組或者vector)。主要包括二分查找,插值查找,斐波拉契查找
2.1二分查找(折半查找)
基本思想:
- (1)與中間元素比較,其中mid=low+1/2*(low+high)
- (2)等於中間元素,則查找成功
- (3)大於中間元素,在它的右半區查找,重複(1);小於中間元素,在它的左半區查找,重複(1),直到找到給定值。
時間複雜度:
最好:O(1)
最壞:O(logn+1)
平均:O(logn)
注:折半查找的前提條件是需要有序表順序存儲,對於靜態查找表,一次排序後不再變化,折半查找能得到不錯的效率。但對於需要頻繁執行插入或刪除操作的數據集來說,維護有序的排序會帶來不小的工作量,那就不建議使用。——《大話數據結構》
2.2插值查找(折半查找升級版)
二分查找:mid=low+1/2*(low+high)
插值查找:mid = low + (key - a[low]) / (a[high] - a[low]) * (high - low),也就是將上述的比例參數1/2改進了,根據關鍵字在整個有序表中所處的位置,讓mid值的變化更靠近關鍵字key,這樣也就間接地減少了比較次數
基本思想:基於二分查找算法,將查找點的選擇改進爲自適應選擇,可以提高查找效率。當然,差值查找也屬於有序查找。
因爲如果在一個有序表中找相對較小的元素(即離low更近一點),就mid向low靠近一點;找相對較大的元素(即離high更近一點),就mid向high靠近一點;這樣效率比較高。但要求表中元素分佈比較均勻。
時間複雜度:O(logn)
注:對於表長較大,而關鍵字分佈又比較均勻的查找表來說,插值查找算法的平均性能比折半查找要好的多。反之,數組中如果分佈非常不均勻,那麼插值查找未必是很合適的選擇。
2.3斐波那契查找
斐波拉契數列:0,1,1,2,3,5,8,13,21,34,F(k)
基本思想:也是二分查找的一種提升算法,通過運用黃金比例的概念在數列中選擇查找點進行查找,提高查找效率。同樣地,斐波那契查找也屬於一種有序查找算法。
-
(1)將有序數組的數值補全,使它的長度等於某個斐波拉契數F(k)-1
-
(2)取low=0,mid=low+F(k-1)-1,high=F(k)-2
-
(3)當給定值小於a[mid]值,在mid前半段查找,且前半段長度爲F(k-1)-1;當給定值大於a[mid]值,在mid後半段查找,且後半段長度爲F(k-2)-1;重複(2)
時間複雜度:O(logn)
因爲斐波拉契查找求mid=low+F(k-1)-1,只有加減法,沒有乘法,這種細微差別相比較前兩種方法要好一些。
# include <stdio.h>
# include <stdlib.h>
# define MAXN 20
int Binary_Search(int *arr, int n, int key);
int BinaryInsert_Search(int *arr, int n, int key);
void Fibonacci(int *f);
int Fibonacci_Search(int *arr, int n, int key);
int main(void)
{
int a[11] = { 0, 1, 16, 24, 35, 47, 59, 62, 73, 88, 99 };
int index; // -1表示失敗
index = Binary_Search(a, 11, 35);
printf("折半查找的結果爲: %d \n", index);
index = BinaryInsert_Search(a, 11, 35);
printf("插值查找的結果爲: %d \n", index);
index = Fibonacci_Search(a, 11, 35);
printf("斐波那契查找的結果爲: %d \n", index);
system("pause");
return 0;
}
//折半查找
int Binary_Search(int *arr, int n, int key)
{
int low, high, mid;
low = 0; //定義最低下標爲記錄首位
high = n-1; //定義最高下標爲記錄末位
while (low <= high)
{
mid = low + (high - low) / 2; //折半
if (key < arr[mid])
{
high = mid - 1;
}
else if (key > arr[mid])
{
low = mid + 1;
}
else
return mid;
}
return -1;
}
//插值查找
//基本思路:二分查找的改進版 只需改一行代碼
// mid = low + (key - a[low]) / (a[high] - a[low]) * (high - low)
int BinaryInsert_Search(int *arr, int n, int key)
{
int low, high, mid;
low = 0;
high = n - 1;
while (low <= high)
{
mid = low + (key - arr[low]) / (arr[high] - arr[low]) * (high - low);
if (key < arr[mid])
{
high = mid - 1;
}
else if (key > arr[mid])
{
low = mid + 1;
}
else
{
return mid;
}
}
return -1;
}
//產生斐波那契數列
void Fibonacci(int *f)
{
f[0] = 1;
f[1] = 1;
for (int i = 2; i < MAXN; ++i)
f[i] = f[i - 2] + f[i - 1];
}
//斐波那契查找
int Fibonacci_Search(int *arr, int n, int key)
{
int i, mid, low = 0, high = n - 1, k = 0;
int F[MAXN];
Fibonacci(F);
while (n > F[k] - 1) //計算出n在斐波那契中的位置
k++;
for (i = n; i < F[k] - 1; ++i) //把數組補全
arr[i] = arr[high];
while (low <= high)
{
mid = low + F[k - 1] - 1; //計算當前分隔的下標 根據fibonacci數列進行黃金分割
if (arr[mid] > key) // 若查找記錄小於當前分割記錄
{
high = mid - 1; //最高下標調整到分割下標的mid-1處
k = k - 1; // 斐波那契數列下標減一位
}
else if (arr[mid] < key) //若查找記錄大於當前分割記錄
{
low = mid + 1; //最低下標調整到分割下標mid+1處
k = k - 2; //斐波那契數列下標減兩位
}
else
{
if (mid <= n) //如果真則找到相應的位置
{
return mid;
}
else
{
return n; //若mid>n說明是補全數值 返回n
}
}
}
return -1;
}
- 二叉排序樹 ( Binary Sort Tree),又稱爲二叉查找樹。它或者是一棵空樹,或者
是具有下列性質的二叉樹。
若它的左子樹不空,則左子樹上所有結點的值均小於它的根結構的值 ;
若它的右子樹不空 ,則右子樹上所有結點的值均大於宮的根結點的值;
它的左、右子樹也分別爲二叉排序樹。
待更新。。。。