Linux C 数据结构—查找
一.查找概述
顺序查找: 编程简单。数据量不太多时,数据没有顺序。
折半查找: 必须是有序数据。 效率较高,比较次数少。
分块查找: 块内无序、块间有序。 块间查找可以使用顺序或者折半查找。 块内顺序查找。
哈希查找: key - value. 通过运算,将值与所在位置建立联系,通过这样的方式,可以快速的查找数据。
实现方法:直接地址/平方取中法/叠加法/质数除余法。
在哈希表中,不可避免出现冲突,如何解决:开放地址法/备用表法/线性探查法/链地址法
二.顺序查找
适用范围: 数据无序,数据量不大的情况。
//练习:编写函数,实现功能:在一个数组中,有20个数据,在此数据中,找到是否有88这样一个数据。
#include <stdio.h>
int find_data(int *p,int n,int value)
{
int i;
for(i=0; i<n; i++)
{
if(p[i] == value)
return i+1;
}
return 0;
}
int main()
{
int a[] = {2,88,4,5,6,7,7,78,899,6,4,2211,3,566,345,8,22,123,42,6};
int n = find_data(a,20,88);
if(n)
printf("Find it!\n");
else
printf("No \n");
}
三.折半查找
适用: 数据有序。
#include <stdio.h>
int find_by_half(int *p,int n,int value)
{
int low = 0,high = n-1,mid;
while(low <= high)
{
mid =( low + high )/2; //找中点。
if(value < p[mid]) //判断大小。 共三种情况。 小于、大于、等于。
{
high = mid - 1;
}
else if(value > p[mid])
{
low = mid + 1;
}
else
{
return mid+1;
}
}
return -1;
}
int main()
{
int a[] = {3,12,18,20,30,40,50,60,70,88,99,100};
int n = find_by_half(a,12,20);
if(n == -1)
printf("Not find\n");
else
printf("Find it ! position :%d\n",n);
}
四.分块查找
特点: 块内无序、块间有序
查找方法: 先找索引表,后对应到数据中的一块位置。
分块查找,有两个表:
索引表。
原始数据表。
#include <stdio.h>
typedef struct
{
int max;
int pos;
}index_t;
//通过索引表查找数据。
int find_by_index(int *p,index_t *t,int value)
{
int i,start = 0,end = 0;
for(i=0; i<4; i++)
{
if(value <= t[i].max)
{
start = t[i].pos-1; //数据在原始表中的起始下标(位置-1)。
if(i == 3)
end = 19; //数据在原始表中的终止位置
else
end = t[i+1].pos;
break; //找到数据所在块之后,要及时退出当前循环。
}
}
for(i=start; i<end; i++) //根据找到的起止位置,在原始表中查找数据。顺序查找即可。
{
if(value == p[i])
{
return i; //返回的是下标。
}
}
return -1;
}
int main()
{
int a[] = {18,10,9,8,16,20,38,42,19,50,84,72,56,55,76,100,90,88,108};
index_t b[4] = {{18,1},{50,6},{84,11},{108,16}};
int n = find_by_index(a,b,42);
if(n == -1)
printf("Not find \n");
else
printf("Pos : %d\n",n+1); //下标值 + 1 = 位置。
}
五.Hash表(又称为散列表)
将表里的数据与其位置建立对应关系。(value-key)
存取数据: 按同样的规则去存取即可。
方法一: 直接地址法。 示例如下:
#include <stdio.h>
int hash_func(int key) //哈希函数,用来建立规则。
{
return key-1;
}
void save_hash(int *p,int age,int value) //使用哈希规则存数据。
{
int index = hash_func(age);
p[index] = value;
}
int find_by_hash(int *p,int age) //使用规则取数据。
{
int pos = hash_func(age);
return p[pos];
}
int main()
{
int a[100] = {0};
int age,num;
while(1)
{
puts("Input age num: ");
scanf("%d%d",&age,&num);
if(age == 0)
break;
save_hash(a,age,num); //存。
}
puts("Search :input age :");
scanf("%d",&age); //取。
num = find_by_hash(a,age);
printf("The num is %d\n",num);
}
方法二: 叠加法: 示例如下:
#include <stdio.h>
int hash_func(int num)
{
int x = num/10000-num/100%100+num%100;
return x;
}
void save_hash(int *p,int num)
{
int index = hash_func(num);
p[index] = num;
}
int find_by_hash(int *p,int num)
{
int pos = hash_func(num);
return p[pos];
}
int main()
{
int num[] = {566765,434322,896756,214657,113565,558867};
int a[1000] = {0};
int i;
for(i=0; i<sizeof(num)/sizeof(int); i++)
{
save_hash(a,num[i]);
}
puts("Search num:");
scanf("%d",&i);
int res = find_by_hash(a,i);
if(res == 0)
printf("Not find\n");
else
printf("I find it !\n");
return 0;
}
方法三: 质数除余法: 示例如下:
注意的点:
- 根据数据的个数,确定要创建的哈希表长。 (n/X) x 填装因子:一般是 0.75.([11/0.75]=15 )
- 确定的质数,要符合的条件: 比表长小的最大的质数。 例如:表长15,选取的质数:13.
如果产生冲突,使用的方法:
备用表法。
开放地址法。
线性探查法。(顺延)(二次探查等)
#include <stdio.h>
int hash_func(int num)
{
return num%13;
}
void save_by_zhi(int *b,int *c,int num)
{
static int index = 0;
int pos = hash_func(num);
if(b[pos] == 0)
{
b[pos] = num;
}
else
{
c[index] = num;
index++;
}
return ;
}
void find_by_zhi(int *b,int *c,int num)
{
int i ;
int pos = hash_func(num);
if(b[pos] == num)
{
printf("Find it! Pos :B: %d\n",pos);
return ;
}
else
{
for(i=0; i<5; i++)
{
if(c[i] == num)
{
printf("Find it! Pos :C: %d\n",i);
return ;
}
}
printf("Not found!\n");
}
return ;
}
int main()
{
int a[] = {23,13,46,77,45,32,8,92,73,75,40};
int b[15] = {0};
int c[5] = {0};
int i;
for(i=0; i<11; i++)
save_by_zhi(b,c,a[i]);
int number;
puts("Search num:");
scanf("%d",&number);
find_by_zhi(b,c,number);
}
hash查找: 直接地址法。 key-value
叠加法。
质数除余法。 n/0.75 = 30, p=29
六. 练习
一个字符串中可能包含a-z中的多个字符,字符也可能重复,例如char a[] = “dfafdafdafdfdffefdf”;
写一个程序,对于给定一个这样的字符串,求出字符串中出现次数最多的那个字母以及出现的次数
(若次数最多的字母有多个,则全部求出)。
#include <stdio.h>
int main()
{
char s[] = "qfdjfgqoyfwqadfqp";
int num[26] = {0};
int i = 0,max = 0;
while(s[i] != '\0') //统计字母出现的次数。 num[0]--> 'a' num[1]--> 'b' , ...
{
num[s[i]-'a']++;
i++;
}
for(i=0; i<26; i++) //获取出现的最大值。
{
if(max < num[i])
max = num[i];
}
for(i=0; i<26; i++) //出现次数最多,且次数相同的字母,及对应出现的次数。
{
if(num[i] == max)
printf("%c : %d\n",i+'a',max);
}
}