查找算法-C
算法的五个特征 : 有穷性、确定性、可行性、输入、输出
算法的设计要求 : 正确性、可读性、健壮性、高效率、低存储
一、顺序查找
从序列的某个位置开始,一直到序列结束,依次比较。
//顺序表
int search(int* arr,size_t len,int key)
{
for(int i=0; i<len; i++)
{
if(arr[i] == key)
return i;
}
return -1;
}
// 从头结点开始,如果找到则返回所在节点的地址,找不到则返回NULL
Node* linear_search(Node* head,int key)
{
for(Node* n=head; NULL!=n; n=n->next)
{
if(n->data == key)
return n;
}
return NULL;
}
二、二分查找
前提:序列有序
思路:
①从序列中间(mid)开始与目标值(key)比较;
②如果相等直接返回 程序结束;
③如果小于key,left=mid+1 如果大于key,right=mid-1;
④如果left<=right 回到①;
//顺序实现
//[left,right]
int binary_search(int* arr, size_t len, int key)
{
int left = 0 , right = len-1;
while(left <= right)
{
int mid = (left + right) / 2;
if(arr[mid] == key)
return mid;
if(arr[mid] > key)
right = mid-1;
if(arr[mid] < key)
left = mid+1;
}
return -1
}
//[left,right)
int binary_search(int* arr, size_t len, int key)
{
int left = 0 , right = len;
while(left < right)
{
int mid = (left + right) / 2;
if(arr[mid] == key)
return mid;
if(arr[mid] > key)
right = mid;
if(arr[mid] < key)
left = mid+1;
}
return -1
}
//递归实现
int _binary_search(int* arr, int left, int right, int key)
{
if(left >= right)
return -1;
int mid = (left + right) / 2;
if(arr[mid] > key)
return _binary_search(arr,left,mid,key);
if(arr[mid] < key)
return _binary_search(arr,mid+1,right,key);
return mid;
}
int binary_search(int* arr, size_t len, int key)
{
return _binary_search(arr,0,len,key);
}
优点:速度快:O(log2n)
缺点:要求数据有序、不适用链表
三、哈希查找
在查找数据时需要进行一系列的比较运算,无论是顺序查找、二分查找,都是建立在比较的基础上的,但最理想的查找算法是不经过任何比较,一次存取就能查找到数据,那么就需要在存储位置和它的关键字之间建立一个确定的对应关系,使每个关键字和数据中的唯一的存储位置相对应。在查找时,根据对应关系找到给定的关键字所对应的数据,这样可以不经过比较可以直接取得所查找的数据。
存储位置与关键字之间的对应关系为哈希函数,按这个思想建立的表为哈希表。
//例如:假定有100万个0~255之间的随机数,然后输入一个0~255之间的整数,查询出该数一共出现了多少次。
for(int i=0; i<1000000; i++)
{
arr[i] = rand() % 256;
}
// 把数据当值作为数组cnts的下标(把关键字与存储位置相对应),直接定值法,H(key)=key
for(int i=0; i<1000000; i++)
{
cnts[arr[i]]++;
}
以上是很简单的一个例子,但是可以看出其局限性,比如如果数据范围变为0~1000000,那么这样构建出来的哈希表可能很大,那么就得重新设计哈希函数,但是这样算出来的结果也可能出现重复,因此设计出合适的哈希函数、解决冲突问题是哈希表和哈希查找的关键。
设计哈希函数的方法:
直接定值法:
取关键字的值或某个线性函数作为k哈希地址:H(key) = key 或H(key)=a*key-b,但这种方法对数据有很高的要求。
数字分析法:
假设以关键字key为基数,并且哈希表中可能出现的数字全部知道,取关键字的某几位为哈希地址,例如学号:
1~2系、3~4为专业、5~6为年级、7~9为入学序号,因此H(key)=key%1000。
解决哈希值冲突的方法:
- 开方地址法
- 再哈希法
- 链地址法
- 创建公共溢出区
哈希查找的优点:
查找速度极快,时间复杂度能达到O(1)。
哈希查找的缺点:
1、局限性比较大,对数据的要求比较高。
2、设计哈希函数麻烦,没具体的设计哈希函数的方法,只是有一些大致的思路。
3、需要建立哈希表,占用了额外的空间。