第 7 章 查找
7.1 查找的定义
查找:在数据集合中寻找满足某种条件的数据元素的过程。
查找表:用于查找的数据集合成为查找表,它由同一类型的数据元素(或记录)组成。
关键字:数据元素中唯一标识该元素的某个数据项的值,使用关键字的查找,查找结果是唯一的。
平均查找长度(ASL,Average Search Length):所有查找过程中进行关键字的比较次数的平均值。
7.2 顺序查找
typedef struct{ //查找表的数据结构(顺序表)
int *elem; //动态数组基地址
int TableLen; //表的长度
}SSTable;
//顺序查找
int Search_Seq(SSTable st,int key)
{
int i;
for(i=0;i<st.TableLen&&st.elem[i]!=key;i++);
//查找成功,则返回元素下标;查找失败,则返回-1
return i==st.TableLen?-1:i;
}
int main() {
int i;
SSTable L; //定义一个顺序表变量
L.elem = (int*)malloc(sizeof(int)*100); //初始动态分配
L.TableLen=0; //初始化表长度
//利用循环给顺序表赋值
for(i=0;i<10;i++)
{
L.elem[i]=i;
L.TableLen+=1;
}
//打印顺序表中的元素
for(i=0;i<10;i++)
printf("%4d",L.elem[i]);
printf("\n");
//查找指定元素在顺序表中的位置,并打印出其在顺序表中的下标
printf("%d\n",Search_Seq(L,5));
printf("%d\n",Search_Seq(L,15));
return 0;
}
运行结果:
7.3 折半查找
仅适用于有序的顺序表。
//折半查找
int Binary_Search(SSTable st,int key)
{
int low=0,high=st.TableLen-1,mid;
while(low<=high){
mid=(low+high)/2; //取中间位置
if(st.elem[mid]==key)
return mid; //查找成功则返回 元素所在位置
else if(st.elem[mid]>key)
high=mid-1; //从前半部分继续查找
else
low=mid+1; //从后半部分继续查找
}
return -1; //查找失败,返回-1
}
7.4 分块查找
//顺序表
typedef struct{ //查找表的数据结构(顺序表)
int *elem; //动态数组基地址
int TableLen; //表的长度
}SSTable;
//索引表
typedef struct{
int maxValue; // 索引区间的最大键值
int low,high; // 索引区间的起止下标
}Index;
//索引表数组
typedef struct{
Index *ind; //动态索引表数组基地址
int TableLen; //表的长度
}IndexList;
//分块查找
int Block_Search(SSTable st, IndexList sy, int key)
{
int i, j;
//顺序查找索引表
// for (i = 0; i < sy.TableLen; i++)
// {
// if (key <= sy.ind[i].maxValue)
// break;
// }
//折半查找索引表
int low = 0, high =sy.TableLen-1;
while (low <= high)
{
int mid = (low + high) / 2;
if (key == sy.ind[mid].maxValue)
{
i = mid;
break;
}
else if (key < sy.ind[mid].maxValue)
high = mid - 1;
else
low = mid + 1;
}
if (low > high)
i = low;
//超出索引表则查找失败
if (i == sy.TableLen)
return -1; //查找失败返回-1
//在顺序表中索引表对应的块中查找
j = sy.ind[i].low;
while (j <= sy.ind[i].high)
{
if (key == st.elem[j])
break;
else
j++;
}
if (j <= sy.ind[i].high)
return j;
else
return -1;
}
在main()中调用分块查找
int main() {
SSTable L; //定义一个顺序表变量
L.elem = (int*)malloc(sizeof(int)*100); //初始动态分配
L.TableLen=14; //初始化表长度
L.elem[0]=7;
L.elem[1]=10;
L.elem[2]=13;
L.elem[3]=19;
L.elem[4]=16;
L.elem[5]=20;
L.elem[6]=27;
L.elem[7]=22;
L.elem[8]=30;
L.elem[9]=40;
L.elem[10]=36;
L.elem[11]=43;
L.elem[12]=50;
L.elem[13]=48;
IndexList SY;
SY.ind = (Index*)malloc(sizeof(Index)*100); //初始动态分配
SY.TableLen=5; //初始化表长度
SY.ind[0].maxValue=10;
SY.ind[0].low=0;
SY.ind[0].high=1;
SY.ind[1].maxValue=20;
SY.ind[1].low=2;
SY.ind[1].high=5;
SY.ind[2].maxValue=30;
SY.ind[2].low=6;
SY.ind[2].high=8;
SY.ind[3].maxValue=40;
SY.ind[3].low=9;
SY.ind[3].high=10;
SY.ind[4].maxValue=50;
SY.ind[4].low=11;
SY.ind[4].high=13;
printf("%d\n",Block_Search(L,SY,19));
printf("%d\n",Block_Search(L,SY,30));
printf("%d\n",Block_Search(L,SY,60));
return 0;
}
数组赋值也可用定义的同时完成初始化的赋值,或键盘输入等赋值方式可使赋值过程更简便。
运行结果:
7.5 二叉查找树
//二叉查找树结点
typedef struct BSTNode{
int key;
struct BSTNode *lchild,*rchild;
}BSTNode,*BSTree;
//二叉查找树
BSTree BST_Search(BSTree T,int key)
{
while(T!=NULL&&key!=T->key)
{
if(key<T->key)
T=T->lchild;
else T=T->rchild;
}
return T;
//使用递归
// if(T==NULL)
// return NULL;
// if(key==T->key)
// return T;
// else if(key<T->key)
// return BST_Search(T->lchild,key);
// else
// return BST_Search(T->rchild,key);
}
int BST_Insert(BSTree *T,int k)
{
if(*T==NULL)
{
*T=(BSTree)malloc(sizeof(BSTNode));
(*T)->key=k;
(*T)->lchild=(*T)->rchild=NULL;
return 1;
}
else if(k==(*T)->key)
return 0;
else if(k<(*T)->key)
return BST_Insert(&((*T)->lchild),k);
else
return BST_Insert(&((*T)->rchild),k);
}
int main() {
BSTree T=NULL;
BST_Insert(&T,19);
printf("%d\n",T->key);
BST_Insert(&T,13);
BST_Insert(&T,11);
printf("%d\n",T->lchild->lchild->key);
BST_Insert(&T,50);
BST_Insert(&T,26);
BST_Insert(&T,21);
BST_Insert(&T,30);
BST_Insert(&T,66);
BST_Insert(&T,60);
BST_Insert(&T,70);
printf("%d\n",T->rchild->rchild->rchild->key);
printf("%d\n",BST_Search(T,60)->key);
return 0;
}
运行结果:
7.6 散列查找(哈希表)
#include <stdio.h>
#include <stdlib.h>
#define HashSize 12
#define Empty -32767 //为空标记
//哈希表
typedef struct
{
int *value;
int hashsize;
}HashMap;
//初始化
void IntiHashMap(HashMap *H)
{
int i;
H->hashsize=HashSize; //初始化哈希表长度
H->value=(int *)malloc(HashSize*sizeof(int)); //创建哈希表数组
for(i=0;i<HashSize;i++) //初始化哈希表为空
{
H->value[i]=Empty;
}
}
//散列函数 (除留余数法)
int Hash(int value)
{
return value%HashSize; //除数也可换成其他更合适的值,如小于HashSize的最大质数
}
//在哈希表中插入数据
void Insert(HashMap *H,int data)
{
int InsertAddress;
InsertAddress=Hash(data);
//发生冲突
while(H->value[InsertAddress]!=Empty)//线性探测
{
InsertAddress=(InsertAddress+1)%HashSize;
}
H->value[InsertAddress]=data;
}
//查找指定元素是否在哈希表中
int Search(HashMap *H,int SeartData)
{
int HashAddress;
HashAddress=Hash(SeartData);
while(H->value[HashAddress]!=SeartData)
{
HashAddress=(HashAddress+1)%HashSize;
if(H->value[HashAddress]==Empty||HashAddress==Hash(SeartData))
{
return -1;
}
}
return HashAddress;
}
int main()
{
HashMap H;
int i;
int a[12]={19,14,23,1,68,20,84,23,11,55,10,79};
IntiHashMap(&H);
for(i=0;i<HashSize;i++)
{
Insert(&H,a[i]);
}
printf("address ");
for(i=0;i<HashSize;i++)
printf("%6d",i);
printf("\n");
printf("a[i] ");
for(i=0;i<HashSize;i++)
printf("%6d",a[i]);
printf("\n");
printf("Hash[i] ");
for(i=0;i<HashSize;i++)
printf("%6d",H.value[i]);
printf("\n");
return 0;
}