查找就是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素。
顺序表查找
顺序表查找(sequential search)又叫线性查找,是最基本的查找技术,它的查找过程是:从表中第一个记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功
,找到所查的记录;如果查到最后一个记录,其关键字和给定值比较都不等时,则表中没有所查的记录,查找不成功
。
- 顺序表查找
a为数组,key为要查找的关键字,a[i]==key则查找成功。 - 顺序表查找优化
以上算法每次循环时都要对i是否越界,即是否小于等于n作判断。事实上,还可以有更好一点的办法,设置一个哨兵
,可以解决不需要每次让i与n作比较,时间复杂度为O(n)
。
有序表查找
折半查找
折半查找又称为二分查找,它的前提是线性表中的记录必须是关键码有序,线性表必须采用顺序存储,时间复杂度O(logn)
。
插值查找
现在我们的问题是,为什么一定要折半,而不是折1/4或者折更多呢?插值查找时根据要查找的关键字key与查找表中最大最小记录的关键字比较后的查找方法,其核心就在于插值的计算公式:
k e y − a [ l o w ] a [ h i g h ] − a [ l o w ] \frac{key-a[low]}{a[high]-a[low]} a[high]−a[low]key−a[low]
mid = low + (high-low)*(key-a[low])/(a[high]-a[low]);
时间复杂度为O(logn),但对于表长较长,而关键字分布又比较均匀
的查找表来说,插值查找算法的平均性能比折半查找好得多。
斐波那契查找
除了插值查找,还可以利用黄金分割原理来实现查找,即斐波那契查找。
- 数组不够斐波那契对应数字长度,得补全a[i]=a[n]
- mid=low+F[k-1]-1
- 如果key<a[mid],则high=mid-1;k=k-1
- 如果key>a[mid],则low=mid+1;k=k-2
- 直到key=a[mid],程序结束
如果mid>n,则说明是补全数值,返回n
#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "math.h"
#include "time.h"
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 /* 存储空间初始分配量 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
int F[100]; /* 斐波那契数列 */
/* 无哨兵顺序查找,a为数组,n为要查找的数组个数,key为要查找的关键字 ,i返回角标*/
int Sequential_Search(int *a, int n, int key)
{
int i;
for (i = 1; i <= n; i++)
{
if (a[i] == key)
return i;
}
return 0;
}
/* 有哨兵顺序查找 */
//a为表,n为表长,key为要查找的数字,i返回数字角标
int Sequential_Search2(int *a, int n, int key)
{
int i;
a[0] = key;
i = n;
while (a[i] != key)
{
i--;
}
return i;
}
/* 折半查找 */
//a为表,n为表长,key为要查找的数字,mid返回数字角标
int Binary_Search(int *a, int n, int key)
{
int low, high, mid;
low = 1; /* 定义最低下标为记录首位 */
high = n; /* 定义最高下标为记录末位 */
while (low <= high)
{
mid = (low + high) / 2; /* 折半 */
if (key<a[mid]) /* 若查找值比中值小 */
high = mid - 1; /* 最高下标调整到中位下标小一位 */
else if (key>a[mid])/* 若查找值比中值大 */
low = mid + 1; /* 最低下标调整到中位下标大一位 */
else
{
return mid; /* 若相等则说明mid即为查找到的位置 */
}
}
return 0;
}
/* 插值查找 */
//a为表,n为表长,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]) /* 若查找值比插值小 */
high = mid - 1; /* 最高下标调整到插值下标小一位 */
else if (key>a[mid])/* 若查找值比插值大 */
low = mid + 1; /* 最低下标调整到插值下标大一位 */
else
return mid; /* 若相等则说明mid即为查找到的位置 */
}
return 0;
}
/* 斐波那契查找 */
//a为表,n为表长,key为要查找的数字,mid返回数字的角标
int Fibonacci_Search(int *a, int n, int key)
{
int low, high, mid, i, k = 0;
low = 1; /* 定义最低下标为记录首位 */
high = n; /* 定义最高下标为记录末位 */
while (n>F[k] - 1)
k++;
for (i = n; i<F[k] - 1; i++)
a[i] = a[n];
while (low <= high)
{
mid = low + F[k - 1] - 1;
if (key<a[mid])
{
high = mid - 1;
k = k - 1;
}
else if (key>a[mid])
{
low = mid + 1;
k = k - 2;
}
else
{
if (mid <= n)
return mid; /* 若相等则说明mid即为查找到的位置 */
else
return n;
}
}
return 0;
}
int main(void)
{
int a[MAXSIZE + 1], i, result;
int arr[MAXSIZE] = {
0,1,16,24,35,47,59,62,73,88,99 };
for (i = 0; i <= MAXSIZE; i++)
{
a[i] = i;
}
result = Sequential_Search(a, MAXSIZE, MAXSIZE);
printf("Sequential_Search:%d \n", result);
result = Sequential_Search2(a, MAXSIZE, 1);
printf("Sequential_Search2:%d \n", result);
result = Binary_Search(arr, 10, 62);
printf("Binary_Search:%d \n", result);
result = Interpolation_Search(arr, 10, 62);
printf("Interpolation_Search:%d \n", result);
F[0] = 0;//斐波那契数列,全局变量
F[1] = 1;
for (i = 2; i < 100; i++)
{
F[i] = F[i - 1] + F[i - 2];
}
result =