一、顺序查找
适用于查找无序数据,时间复杂度为O(n).
算法过程:从一端开始逐元素与给定的key值比较。
1、 无哨兵的算法
int SeqSearch(int *arr, int length, int key)
{
for(int i=0; i<length; --i)
{
if(arr[i] == key)
{
return i;
}
}
return -1; //查找失败则返回-1
}
2、有哨兵的算法
int SeqSearch(int *arr, int length, int key)
{
arr[0] = key; //0号位置不保存数据,作为哨兵使用
int i;
for(i=length; arr[i] != key; --i)
{
;
}
return i; //返回查找结果,查找失败则返回0
}
有哨兵的算法的优势:在每次循环中都要少一次对下标是否越界的判断,时间效率有所提高。
二、二分查找
适用于有序排列,时间复杂度为O(logn).
算法过程:先取位于序列中间的元素,将其与查找键key比较。如果它们的值相等,则找到。否则将查找区间缩小一半。
假定数据按升序排列:
int BinarySearch(int *arr, int length, int key)
{
int left=0, right=length-1, mid;
while(left <= right)
{
mid = left + (right - left)/2;
if( key == arr[mid])
{
return mid;
}
else if(key < arr[mid])
{
right = mid - 1;
}
else
{
left = mid + 1;
}
} // end of while
return -1; //查找失败返回-1
}
注:在计算mid时,使用mid = left + (right - left)/2,而不用mid = (left + right)/2。因为left与right之和可能超过int极限值,发生数值溢出,所以使用减法代替加法。
三、哈希表查找
哈希表实际上是一个具有固定大小的数组,其中每条记录的存储位置和它的关键字之间有一个确定的映射关系(哈希函数)。哈希表查找、插入、删除的平均时间复杂度为O(1)。
哈希冲突:不同的关键字经过哈希函数映射后得到相同哈希地址的现象。产生原因:关键字的取值范围大于表长。
1、哈希函数
采用最简单最常用的除数取余法。
int hash(int key)
{
return key % HASHTABLESIZE;
}
2、解决哈希冲突
以链地址法为例。哈希表中存放的是产生冲突的所有关键字构成的单链表的表头。
(1)、哈希表结构
#include<stdio.h>
#include<stdlib.h>
#define HASHTABLESIZE 11
typedef struct tagHashNode
{
int data;
struct tagHashNode *next;
} HashNode, *HashTable;
HashTable hashTable[HASHTABLESIZE];
(2)、哈希表初始化
void initHashTable(HashTable *hashTable)
{
for(int i=0; i<HASHTABLESIZE; ++i)
{
hashTable[i] = NULL;
}
}
(3)、哈希表插入
算法过程:根据哈希函数求出关键字key的哈希地址。若该地址为空,则直接插入该节点。否则,遍历单链表到尾节点,再插入。
int insertHashTable(HashTable *hashTable, int key)
{
int index = hash(key);
HashNode *newNode = (HashNode *)malloc(sizeof(HashNode));
if(newNode == NULL)
{
return -1;//内存申请失败
}
newNode->data = key;
newNode->next = NULL;
if(hashTable[index] == NULL)
{
hashTable[index] = newNode;
}
else
{
HashNode *pTempNode = hashTable[index];
while( pTempNode->next != NULL)
{
pTempNode = pTempNode->next;
}
pTempNode->next = newNode;
}
return 0;
}
(4)、哈希表查找
算法过程:根据哈希函数求得关键key对应的哈希地址。若该地址为空,则查找失败。否则,遍历单链表并比较key与节点中的值。若找到则将数据用node取回。
int searchHashTable(const HashTable *hashTable, int key, HashNode *node)
{
int index = hash(key);
HashNode *pTempNode = hashTable[index];
while(pTempNode != NULL )
{
if(pTempNode->data == key)
{
*node = *pTempNode;
return 0;
}
pTempNode = pTempNode->next;
}
return -1;//查找失败
}
完整代码如下:
#include<stdio.h>
#include<stdlib.h>
#define HASHTABLESIZE 11
typedef struct tagHashNode
{
int data;
struct tagHashNode *next;
} HashNode, *HashTable;
int hash(int key)
{
return key % HASHTABLESIZE;
}
void initHashTable(HashTable *hashTable)
{
for(int i=0; i<HASHTABLESIZE; ++i)
{
hashTable[i] = NULL;
}
}
int insertHashTable(HashTable *hashTable, int key)
{
int index = hash(key);
HashNode *newNode = (HashNode *)malloc(sizeof(HashNode));
if(newNode == NULL)
{
return -1;//内存申请失败
}
newNode->data = key;
newNode->next = NULL;
if(hashTable[index] == NULL)
{
hashTable[index] = newNode;
}
else
{
HashNode *pTempNode = hashTable[index];
while( pTempNode->next != NULL)
{
pTempNode = pTempNode->next;
}
pTempNode->next = newNode;
}
return 0;
}
void showHashTable(HashTable *hashTable)
{
HashNode *pTempNode = NULL;
for(int i=0; i<HASHTABLESIZE; ++i)
{
printf("index: %d\n",i);
pTempNode = hashTable[i];
if(pTempNode == NULL)
{
printf("NULL\n\n");
continue;
}
while(pTempNode != NULL )
{
printf("%d ", pTempNode->data);
pTempNode = pTempNode->next;
}
printf("\n\n");
}// end of for
}
int searchHashTable(const HashTable *hashTable, int key, HashNode *node)
{
int index = hash(key);
HashNode *pTempNode = hashTable[index];
while(pTempNode != NULL )
{
if(pTempNode->data == key)
{
*node = *pTempNode;
return 0;
}
pTempNode = pTempNode->next;
}
return -1;//查找失败
}
void test()
{
/* code */
int arr[10] = {0,1,4,9,16,25,36,49,64,81};
HashTable hashTable[HASHTABLESIZE];
initHashTable(hashTable);
for(int i=0; i<10; i++)
{
insertHashTable(hashTable, arr[i]);
}
showHashTable(hashTable);
HashNode node;
int status;
int key = 3;
status = searchHashTable(hashTable, key, &node);
printf("Try to find the key:%d, ", key);
if(status == 0)
{
printf("and successful!\n", node.data);
}
else{
printf("but failed!\n");
}
key = 49;
status = searchHashTable(hashTable, key, &node);
printf("Try to find the key:%d, ", key);
if(status == 0)
{
printf("and successful!\n", node.data);
}
else{
printf("but failed!\n");
}
}
int main(int argc, char const *argv[])
{
test();
return 0;
}
运行结果:
index: 0
0
index: 1
1
index: 2
NULL
index: 3
25 36
index: 4
4 81
index: 5
16 49
index: 6
NULL
index: 7
NULL
index: 8
NULL
index: 9
9 64
index: 10
NULL
Try to find the key:3, but failed!
Try to find the key:49, and successful!
本文介绍了三种常用的数据查找算法:顺序查找、二分查找和哈希表查找。顺序查找适用于无序数据,时间复杂度为O(n);二分查找适用于有序数据,时间复杂度为O(logn);哈希表查找通过哈希函数实现快速查找,平均时间复杂度为O(1),并讨论了哈希冲突的解决方法。示例代码展示了哈希表的创建、插入和查找操作。
1万+

被折叠的 条评论
为什么被折叠?



