1.顺序查找
顺序查找又叫线性查找,是最基本的查找技术,它的查找过程是:从第一个(或者最后一个)记录开始,逐个进行记录的关键字和给定值进行比较,若某个记录的关键字和给定值相等,则查找成功。如果查找了所有的记录仍然找不到与给定值相等的关键字,则查找不成功。
首先是一种最直觉的实现方法
// 顺序查找,a为要查找的数组,n为要查找的数组的长度,key为要查找的关键字
int Sq_Search(int *a, int n, int key) //其中的 *a 的含义是数组的头指针,传入头指针相当于传入了这个数组
{
int i;
for( i=1; i <= n; i++ )
{
if( a[i] == key )
{
return i;
}
}
return 0;
}
优化方案
// 顺序查找优化方案,a为要查找的数组,n为要查找的数组的长度,key为要查找的关键字
int Sq_Search(int *a, int n, int key)
{
int i = n;
a[0] = key
while( a[i] != key )
{
i--;
}
return i;
}
2.折半查找
如果从文件中读取的数据记录的关键字是有序排列的,则可以用一种效率比较高的查找方法来查找文件的记录,这就是折半查找法,又称为二分法搜索。它的基本思想,减小查找序列的长度,分而治之地进行关键字的查找。先确定待查找记录的所在范围,然后逐渐缩小这个范围,直到找到该记录或查找失败(查无该记录)为止。
迭代实现
#include <stdio.h>
int bin_search( int str[], int n, int key )
{
int low, high, mid;
low = 0;
high = n-1;
while( low <= high )
{
mid = (low+high)/2;
if( str[mid] == key )
{
return mid; // 查找成功
}
if( str[mid] < key )
{
low = mid + 1; // 在后半序列中查找
}
if( str[mid] > key )
{
high = mid - 1; // 在前半序列中查找
}
}
return -1; // 查找失败
}
int main()
{
int str[11] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89};
int n, addr;
printf("请输入待查找的关键字: ");
scanf("%d", &n);
addr = bin_search(str, 11, n);
if( -1 != addr )
{
printf("查找成功, 关键字 %d 所在的位置是: %d\n", n, addr);
}
else
{
printf("查找失败!\n");
}
return 0;
}
递归实现
#include<stdio.h>
#define SIZE 10
typedef int ElemType;
int refind(ElemType *data,int begin,int end,ElemType num);
int main(void){
ElemType data[SIZE]={10,20,30,40,50,60,70,80,90,100};
ElemType num;
for(int i = 0;i<SIZE;i++)
printf("%d ",data[i]);
printf("\n请输入要查找的数据:\n");
scanf("%d",&num);
int flag = refind(data,0,SIZE,num);
printf("位置为:%d\n",flag);
return 0;
}
/
//递归
int refind(ElemType *data,int begin,int end,ElemType num)
{
if(begin > end)
{
printf("没找到\n");
return -1;
}
int mid = (begin+end)/2;
if(data[mid] == num)
{
return mid;
}else if(data[mid] <= num)
return refind(data,mid+1,end,num);
else
return refind(data,begin,mid-1,num);
}
3.插值查找
在上面的折半查找法中,每次都是对折之后再查找,但是实际上是可以不进行对折查找。比如说,我们在英语字典中查找某一个英语单词,首先会翻到这个单词的首字母的位置再进行查找,这种查找方式就叫做按比例查找。
4.斐波那契查找(黄金分割法查找)
我们知道黄金分割比是0.618:1,但是这个比例实际上和斐波那契数列也是有关系的。斐波那契查找就是在二分查找的基础上根据斐波那契数列进行分割的。在斐波那契数列找一个等于略大于查找表中元素个数的数F[n],将原查找表扩展为长度为F[n](如果要补充元素,则补充重复最后一个元素,直到满足F[n]个元素),完成后进行斐波那契分割,即F[n]个元素分割为前半部分F[n-1]个元素,后半部分F[n-2]个元素,找出要查找的元素在那一部分并递归,直到找到。
#include <stdio.h>
#define MAXSIZE 20
void fibonacci(int *f) //使用递推关系生成斐波那契数列
{
int i;
f[0] = 1;
f[1] = 1;
for(i=2; i < MAXSIZE; ++i)
{
f[i] = f[i-2] + f[i-1];
}
}//f[i] 1 1 2 3 5 8 13 21 34 55 89
// i 0 1 2 3 4 5 6 7 8 9 10
// *a 是待查找数组的头指针,key 待查找的数字,n 是待查找数组中元素的个数
a[i] 1, 5, 15, 22, 25, 31, 39, 42, 47, 49, 59, 68, 88
//若 key=39 n=13
int fibonacci_search(int *a,int key,int n)
{
int low = 0;
int high = n - 1;//high=13-1 下标从0开始
int mid = 0;
int k = 0;
int F[MAXSIZE];
int i;
fibonacci(F);
//计算n位于斐波那契数列的位置
while( n > F[k]-1 )
{
++k;
}
//如果数组的长度小于对应的斐波那契数列中元素的值,那么将他用最大值拓展
// 补充的元素值为最后一个元素的值
//将a的元素扩展到(某斐波那契数 - 1),即F[k]-1
for( i=n; i < F[k]-1; ++i)
{
a[i] = a[high];
}
while( low <= high )
{ // low:起始位置 0
// 前半部分有f[k-1]个元素,由于下标从0开始
// 则-1 获取 黄金分割位置元素的下标
mid = low + F[k-1] - 1;//计算当前分割的下标
if( a[mid] > key )//a[5]=31
{
// 查找前半部分,高位指针移动
high = mid - 1;
// (全部元素) = (前半部分)+(后半部分)
// f[k] = f[k-1] + f[k-2]
// 因为前半部分有f[k-1]个元素,所以 k = k-1
k = k - 1;
}
else if( a[mid] < key )//a[5]=31<39
{
// 查找后半部分,高位指针移动
low = mid + 1;
// (全部元素) = (前半部分)+(后半部分)
// f[k] = f[k-1] + f[k-2]
// 因为后半部分有f[k-2]个元素,所以 k = k-2
k = k - 2;
}
else
{
if( mid <= high )
{
//若相当则说明mid即为查找到的位置
return mid;
}
else
{
//若mid>n则说明是扩展的数值,返回n
return high;
}
}
}
return -1;
}
int main()
{
int a[MAXSIZE] = {1, 5, 15, 22, 25, 31, 39, 42, 47, 49, 59, 68, 88};
int key;
int pos;
printf("请输入要查找的数字:");
scanf("%d", &key);
pos = fibonacci_search(a, key, 13);
if( pos != -1 )
{
printf("\n查找成功,关键字 %d 所在的位置是: %d\n\n", key, pos);
}
else
{
printf("\未在数组中找到元素:%d\n\n", key);
}
return 0;
}