数据结构中查找分为如下部分:
- 静态查找表
- 动态查找表
- 哈希表及其查找
以下分别对数据结构中的查找算法进行描述
一、静态查找表
1.顺序表查找
顺序查找(Sequential Search)又称为线性查找,是一种最简单的查找方法。
查找过程如下:
从线性表的一端开始顺序扫描线性表,依次将扫描到的结点关键字和给定值进行比较。
若当前扫描到的结点关键字与给定值相等,则查找成功;
若扫描结束后,仍未能找到关键字等于给定值的结点,则查找失败。
代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#define MAX 11
typedef int key_type;
typedef struct element
{
key_type key; //关键字
}ele;
int seq_search(ele e[], key_type key, int count)
{
int i = 0;
while(e[i].key != key && i < count)
{
i++;
}
if(i < count)
{
return(i + 1);
}
else
{
return -1;
}
}
int main(int argc, char** argv)
{
ele linelist[MAX] = {1, 5, 9, 7, 12, 11, 10, 8, 6, 2, 3};
int count = 11;
int i = 0;
key_type key = 8;
printf("线性表中的元素为:\n");
while(i < count)
{
printf("%d\n", linelist[i].key);
i++;
}
printf("\n关键字[%d]在线性表中的位置为[%d]\n", key, seq_search(linelist, key, count));
system("pause");
return 0;
}
其优点是:该算法简单且适应面广。它对表的结构无任何要求,无论记录是否按关键字有序。
2.有序表查找(折半查找)
当静态查找表为有序表示,那么可以使用折半查找算法来查找,
折半查找(Binary Search)的查找过程如下:
先确定待查记录所在的范围(区间),然后逐步缩小范围 知道找到或找不到该记录为止。
它对线性表的要求是:关键字值按递增或递减顺序排列。
首先,将要查找的关键字k与中间位置结点的关键字比较,中间结点把线性表分为了两个子表,
若比较结果相等,则查找结束。
若不相等,再根据关键字与该中间结点关键字的 比较结果确定下一步在哪个子表区间内查找。这样递归进行下去。
直到找到满足条件的结点或该线性表中没有这样的结点。
代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#define MAX 12
typedef int key_type;
typedef struct element
{
key_type key; //关键字
}ele;
int binary_search(ele* e, key_type key, int count)
{
int i = -1;
int low = 0;
int high = count - 1;
int mid;
while(low < high)
{
mid = (low + high) / 2;
if(key < e[mid].key)
high = mid - 1;
else if(key > e[mid].key)
low = mid + 1;
else
{
i = mid;
break;
}
}
if(i < 0)
return -1;
else
return (i + 1);
}
int main(int argc, char** argv)
{
ele linelist[MAX] = {3, 5, 6, 8, 9, 12, 17, 23, 30, 35, 39, 42};
int count = 11;
int i = 0;
key_type key = 8;
printf("线性表中的元素为:\n");
while(i < count)
{
printf("%d\n", linelist[i].key);
i++;
}
printf("\n关键字[%d]在线性表中的位置为[%d]\n", key, binary_search(linelist, key, count));
system("pause");
return 0;
}
折半查找算法的平均查找长度为O(logn),与顺序查找方法相比,折半查找算法的效率高。速度比顺序查找快。
但折半查找只能使用于有序表,需要对n个元素预先进行排序(仅限于顺序存储结构,对于线性链表无法in性折半查找)。
3. 索引顺序表查找
索引顺序查找,又称分块查找。是顺序查找的一种改进。其性能介于顺序查找和折半查找之间。
分块查找把线性表分成若干块,每一块中的元素存储顺序是任意的,但是块与块之间必须是按关键字大小排序(即前一块中的最大关键字大于(或小于)后一块中的最小(或最大)关键字值)。
另外,需要建立一个索引表,索引表中的一项对应线性表中的一项,索引项由关键字域和链域组成,关键字域存放相应块的最大关键字,链域存放指向本块第一个结点的指针,链域存放指向本块第一个结点的指针,索引表按关键字值递增(或递减)顺序排列。
分块查找的函数分为如下两步:
a)首先确定待查找的结点属于哪一块,即查找所在的块;
b)然后,在块内查找要查的结点。
由于索引表是递增有序的,采用折半查找时,
块内元素个数较少,采用顺序查找在块内查找,
代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#define MAX 16
typedef int key_type;
typedef struct element
{
key_type key; //关键字
}ele;
typedef struct _index
{
key_type key;
int low, high;
}index;
int index_search(ele* e, key_type key, int count, index *idx, int idx_length)
{
int i;
int low = 0;
int high = idx_length - 1;
int mid;
//从块的索引表中查找关键字所在的块(使用折半查找法)
while(low <= high)
{
mid = (low + high) / 2;
if(key < idx[mid].key)
high = mid - 1;
else if(key > idx[mid].key)
low = mid + 1;
else
{
break;
}
}
//从块中查找关键值(使用顺序查找)
i = idx[mid].low;
while(i < idx[mid].high && e[i].key != key)
i++;
if(i > idx[mid].high)
return -1;
else
return i + 1;
}
int main(int argc, char** argv)
{
ele linelist[MAX] = {
8, 20, 13, 17,
40, 42, 45, 32,
49, 58, 50, 52,
67, 79, 78, 80
};
int count = sizeof(linelist)/sizeof(ele);
int i = 0;
key_type key = 50;
//建立索引表
index index_table[4] ={{20,0,3}, {45,4,7}, {58,8,11}, {80,12,15}};
int idx_length = sizeof(index_table)/sizeof(index);
printf("线性表中的元素为:\n");
while(i < count)
{
printf("%d\n", linelist[i].key);
i++;
}
printf("\n关键字[%d]在线性表中的位置为[%d]\n", key, index_search(linelist, key, count, index_table, idx_length));
system("pause");
return 0;
}
存在一问题:如何对给定的数据序列进行分块,本例中是手动进行的分块
索引表查找算法:实际上进行了两次查找(折半查找+顺序查找)。因此整个算法的平均查找长度是两次查找的平均查找长度之和。