查找算法笔记
2015-09-17 21:06
309 查看
顺序查找
顺序表的查找分为三种。简单顺序查找、有序表的二分查找、索引表的顺序查找。这里主要介绍前两种。
一、简单顺序查找
简单顺序查找对数据表的特性没有要求,即是否具有递增递减特性基本不影响查找的性能。基本就是从表的一段开始逐个比较元素,若找到则返回元素在表中对应位置;否则,则返回一个无意义的位置标识。
值得一提的是设置监视哨这一思想,将a[0]设置成监视哨则可以避免每次比较元素后都需要判断下标是否越界这一问题,从而节省了时间。当然,a[0]中将不能在存放有效元素。
下面介绍一个以整型数组为例的查找实现:
[cpp] view plaincopyprint?
1. /*直接顺序查找*/
2. int sequential_search(int a[],int n,int key) //n为数组元素个数,key为待查找元素
3. {
4. int i=n;
5. a[0]=key; //a[0]是监视哨
6.
7. while(a[i]!=key) //若数组中无key,则一定会得到a[0]=key
8. i--;
9.
10. return i; //查找失败返回0
11. }
[cpp] view plaincopyprint?
1. /*直接顺序查找*/
2. int sequential_search(int a[],int n,int key) //n为数组元素个数,key为待查找元素
3. {
4. int i=n;
5. a[0]=key; //a[0]是监视哨
6.
7. while(a[i]!=key) //若数组中无key,则一定会得到a[0]=key
8. i--;
9.
10. return i; //查找失败返回0
11. }
有序表的二分查找
显然二分查找要求表是升序或降序的。并利用有序这一特性改善了查找性能。那么,若原始表无序又该如何呢?排序呗!
以升序表为例:
二分查找的基本过程如下:设查找变量首尾下标分别用low和high标志,将待查关键字和上述区域的中间元素比较,中间元素下标为mid=(low+high)/2,并根据比较结果,分别作以下处理,
①key==a[mid],查找成功,返回mid的值;
②key<a[mid],则继续查找,查找区域变成low=low,high=mid-1。
③key>a[mid],也继续查找,查找区域变成low=mid+1,high=high。
现在,又出现了另一个关键问题:查找何时结束?显然,若查找到key了,返回位置即是结束;如果表中没有key则是当low>high是结束。
1. <pre name="code" class="cpp">#include<stdio.h>
2. int main(){
3. //折半查找函数声明
4. int binSearch(int key,int *data,int dataSize);
5. int binSearchByRecursive(int key,int *data,int head,int tail);
6.
7. int key;
8. int position;//要查找的数在数据中的位置
9. int dataSize=10;
10. int data[10]={1,2,3,4,5,6,7,8,9,10};
11. int i=0;
12. for(;i<dataSize;i++){
13. printf("%d ",data[i]);
14. }
15. printf("\n调用普通折半查找函数,输入要查找的数字:");
16. scanf("%d",&key);
17. printf("\n");
18. //调用折半查找函数
19. position=binSearch(key,data,dataSize);
20. if(position==-1){
21. printf("没有找到\n");
22. }
23. else if(position==-2){
24. printf("参数有误\n");
25. }
26. else{
27. printf("找到数据:%d ,数组下标%d\n",data[position],position);
28. }
29.
30.
31. printf("\n调用递归法折半查找函数,输入要查找的数字:");
32. scanf("%d",&key);
33. printf("\n");
34. //调用折半查找递归法函数
35. position=binSearchByRecursive(key,data,0,dataSize);
36.
37. if(position==-1){
38. printf("没有找到\n");
39. }
40. else if(position==-2){
41. printf("参数有误\n");
42. }
43. else{
44. printf("找到数据:%d ,数组下标%d\n",data[position],position);
45. }
46. }
47.
48. /**
49. 折半查找函数
50. 返回-1没有找到,-2参数有误,大于0表示位置
51. */
52. int binSearch(int key,int *data,int dataSize){
53. int head;
54. int tail;
55. int middle;
56.
57. if(&key==NULL||data==NULL||&dataSize==NULL){
58. return -2;
59. }
60. head=0;
61. tail=dataSize-1;
62. middle=(head+tail)/2;
63.
64. //当不等于中间下标值时继续比较,一直到头下标和尾下标相等时退出比较
65. //此时已全部比较完
66. while(key!=data[middle]&&head!=tail){
67. if(key>data[middle])
68. {
69. head=middle+1;
70. }
71. if(key<data[middle])
72. {
73. tail=middle-1;
74. }
75. middle=(head+tail)/2;
76. }
77.
78. if(key==data[middle]) return middle;
79. else
80. return -1;
81. }
82.
83. /**
84. 折半查找递归法
85. */
86. int binSearchByRecursive(int key,int *data,int head,int tail){
87.
88. int middle;
89. middle=(head+tail)/2;
90.
91. if(key==data[middle])
92. {
93. return middle;
94. }
95.
96. if(head==tail)
97. {
98. return -1;
99. }
100.
101. if(key<data[middle]){
102. return binSearchByRecursive(key,data,head,tail-1);
103. }
104. if(key>data[middle]){
105. return binSearchByRecursive(key,data,head+1,tail);
106. }
107.
108. }
分块查找
秘诀:先分块,再匹配。分而治之
步骤:
1.先取各块中的最大关键字构成一个索引表。
2.查找分为两部分,先对索引表进行二分查找或是顺序查找,以确定待查记录在哪一块中。
3.然后,在已经确定的块中用顺序法进行查找。
分块查找的性能介于顺序查找和对半查找之间。
分块查找的优点:
1.在表中插入或删除一个记录时,只要找到该记录所属的块,就在该块内进行插入和删除运算。
2.因为块内记录的存放是任意的,所以插入或删除比较容易,无须移动大量记录。
缺点:分块查找算法的主要代价是增加一个辅助数组的存储空间。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
struct indexBlock//定义块的结构
{
int key;
int start;
int endx;
}indexBlock[4]; //定义结构体数组
int blockSearch(int x, int a[])
{
int i=0;
int j;
while(i<3 && x>indexBlock[i].key)//确定在哪个块中
i++;
if(i>=3)//大于分的块数,则返回-1,找不到该数
return -1;
j=indexBlock[i].start; //j等于块范围的起始值
while(j<=indexBlock[i].endx && a[j]!=x)//在确定的块内进行查找
j++;
if(j>indexBlock[i].endx)//如果大于块范围的结束值,则说明没有要查找的数,j置为-1
j=-1;
return j;
}
int main()
{
int j=0,k,x;
int a[20];
int i;
for(i=0;i<16;i++)
{
a[i]=i+1;
}
printf("已知有一组数组\n");
for(i=0;i<16;i++)
{
printf("%d ",a[i]);
}
printf("\n");
for(i=0;i<3;i++)
{
indexBlock[i].start=j+1; //确定每个块范围的起始值
j=j+1;
indexBlock[i].endx=j+4; //确定每个块范围的结束值
j=j+4;
indexBlock[i].key=a[j]; //确定每个块范围中元素的最大值
}
printf("请输入你要查找的数字\n");
scanf("%d",&x);
k=blockSearch(x,a);
if(k>=0)
{
printf("查找成功,你要查找的数字在数组中的位置为%d\n",k+1);
}
else
{
printf("查找失败\n");
}
}
顺序表的查找分为三种。简单顺序查找、有序表的二分查找、索引表的顺序查找。这里主要介绍前两种。
一、简单顺序查找
简单顺序查找对数据表的特性没有要求,即是否具有递增递减特性基本不影响查找的性能。基本就是从表的一段开始逐个比较元素,若找到则返回元素在表中对应位置;否则,则返回一个无意义的位置标识。
值得一提的是设置监视哨这一思想,将a[0]设置成监视哨则可以避免每次比较元素后都需要判断下标是否越界这一问题,从而节省了时间。当然,a[0]中将不能在存放有效元素。
下面介绍一个以整型数组为例的查找实现:
[cpp] view plaincopyprint?
1. /*直接顺序查找*/
2. int sequential_search(int a[],int n,int key) //n为数组元素个数,key为待查找元素
3. {
4. int i=n;
5. a[0]=key; //a[0]是监视哨
6.
7. while(a[i]!=key) //若数组中无key,则一定会得到a[0]=key
8. i--;
9.
10. return i; //查找失败返回0
11. }
[cpp] view plaincopyprint?
1. /*直接顺序查找*/
2. int sequential_search(int a[],int n,int key) //n为数组元素个数,key为待查找元素
3. {
4. int i=n;
5. a[0]=key; //a[0]是监视哨
6.
7. while(a[i]!=key) //若数组中无key,则一定会得到a[0]=key
8. i--;
9.
10. return i; //查找失败返回0
11. }
有序表的二分查找
显然二分查找要求表是升序或降序的。并利用有序这一特性改善了查找性能。那么,若原始表无序又该如何呢?排序呗!
以升序表为例:
二分查找的基本过程如下:设查找变量首尾下标分别用low和high标志,将待查关键字和上述区域的中间元素比较,中间元素下标为mid=(low+high)/2,并根据比较结果,分别作以下处理,
①key==a[mid],查找成功,返回mid的值;
②key<a[mid],则继续查找,查找区域变成low=low,high=mid-1。
③key>a[mid],也继续查找,查找区域变成low=mid+1,high=high。
现在,又出现了另一个关键问题:查找何时结束?显然,若查找到key了,返回位置即是结束;如果表中没有key则是当low>high是结束。
1. <pre name="code" class="cpp">#include<stdio.h>
2. int main(){
3. //折半查找函数声明
4. int binSearch(int key,int *data,int dataSize);
5. int binSearchByRecursive(int key,int *data,int head,int tail);
6.
7. int key;
8. int position;//要查找的数在数据中的位置
9. int dataSize=10;
10. int data[10]={1,2,3,4,5,6,7,8,9,10};
11. int i=0;
12. for(;i<dataSize;i++){
13. printf("%d ",data[i]);
14. }
15. printf("\n调用普通折半查找函数,输入要查找的数字:");
16. scanf("%d",&key);
17. printf("\n");
18. //调用折半查找函数
19. position=binSearch(key,data,dataSize);
20. if(position==-1){
21. printf("没有找到\n");
22. }
23. else if(position==-2){
24. printf("参数有误\n");
25. }
26. else{
27. printf("找到数据:%d ,数组下标%d\n",data[position],position);
28. }
29.
30.
31. printf("\n调用递归法折半查找函数,输入要查找的数字:");
32. scanf("%d",&key);
33. printf("\n");
34. //调用折半查找递归法函数
35. position=binSearchByRecursive(key,data,0,dataSize);
36.
37. if(position==-1){
38. printf("没有找到\n");
39. }
40. else if(position==-2){
41. printf("参数有误\n");
42. }
43. else{
44. printf("找到数据:%d ,数组下标%d\n",data[position],position);
45. }
46. }
47.
48. /**
49. 折半查找函数
50. 返回-1没有找到,-2参数有误,大于0表示位置
51. */
52. int binSearch(int key,int *data,int dataSize){
53. int head;
54. int tail;
55. int middle;
56.
57. if(&key==NULL||data==NULL||&dataSize==NULL){
58. return -2;
59. }
60. head=0;
61. tail=dataSize-1;
62. middle=(head+tail)/2;
63.
64. //当不等于中间下标值时继续比较,一直到头下标和尾下标相等时退出比较
65. //此时已全部比较完
66. while(key!=data[middle]&&head!=tail){
67. if(key>data[middle])
68. {
69. head=middle+1;
70. }
71. if(key<data[middle])
72. {
73. tail=middle-1;
74. }
75. middle=(head+tail)/2;
76. }
77.
78. if(key==data[middle]) return middle;
79. else
80. return -1;
81. }
82.
83. /**
84. 折半查找递归法
85. */
86. int binSearchByRecursive(int key,int *data,int head,int tail){
87.
88. int middle;
89. middle=(head+tail)/2;
90.
91. if(key==data[middle])
92. {
93. return middle;
94. }
95.
96. if(head==tail)
97. {
98. return -1;
99. }
100.
101. if(key<data[middle]){
102. return binSearchByRecursive(key,data,head,tail-1);
103. }
104. if(key>data[middle]){
105. return binSearchByRecursive(key,data,head+1,tail);
106. }
107.
108. }
分块查找
秘诀:先分块,再匹配。分而治之
步骤:
1.先取各块中的最大关键字构成一个索引表。
2.查找分为两部分,先对索引表进行二分查找或是顺序查找,以确定待查记录在哪一块中。
3.然后,在已经确定的块中用顺序法进行查找。
分块查找的性能介于顺序查找和对半查找之间。
分块查找的优点:
1.在表中插入或删除一个记录时,只要找到该记录所属的块,就在该块内进行插入和删除运算。
2.因为块内记录的存放是任意的,所以插入或删除比较容易,无须移动大量记录。
缺点:分块查找算法的主要代价是增加一个辅助数组的存储空间。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
struct indexBlock//定义块的结构
{
int key;
int start;
int endx;
}indexBlock[4]; //定义结构体数组
int blockSearch(int x, int a[])
{
int i=0;
int j;
while(i<3 && x>indexBlock[i].key)//确定在哪个块中
i++;
if(i>=3)//大于分的块数,则返回-1,找不到该数
return -1;
j=indexBlock[i].start; //j等于块范围的起始值
while(j<=indexBlock[i].endx && a[j]!=x)//在确定的块内进行查找
j++;
if(j>indexBlock[i].endx)//如果大于块范围的结束值,则说明没有要查找的数,j置为-1
j=-1;
return j;
}
int main()
{
int j=0,k,x;
int a[20];
int i;
for(i=0;i<16;i++)
{
a[i]=i+1;
}
printf("已知有一组数组\n");
for(i=0;i<16;i++)
{
printf("%d ",a[i]);
}
printf("\n");
for(i=0;i<3;i++)
{
indexBlock[i].start=j+1; //确定每个块范围的起始值
j=j+1;
indexBlock[i].endx=j+4; //确定每个块范围的结束值
j=j+4;
indexBlock[i].key=a[j]; //确定每个块范围中元素的最大值
}
printf("请输入你要查找的数字\n");
scanf("%d",&x);
k=blockSearch(x,a);
if(k>=0)
{
printf("查找成功,你要查找的数字在数组中的位置为%d\n",k+1);
}
else
{
printf("查找失败\n");
}
}
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例