数据结构(10)之查找
1 前言
这节我们简单的介绍一下常见的查找算法。
2 详述
2.1 查找概论
查找表(Search Table)是由同一类型的数据元素(或记录)构成的集合。
关键字(Key)是数据元素中某个数据项的值,又称为键值。
可以识别多个数据元素(或记录)的关键字,我们称为次关键字(Secondary Key)。
查找(Searching)就是根据给定的某个值,在查找中确定一个其关键字等于给定的数据元素(或记录)。
查找按照操作方式来分有两大种:静态查找表和动态查找表。
静态查找表(Static Search Table):只做查找操作的查找表。
(1)查询某个“特定的”数据元素是否在查找表中。
(2)检索某个“特定的”数据元素和各种属性。
动态查找表(Dynamic Search Table):在查找过程中同时插入查找表中不存在的数据元素,或者从查找表中删除已经存在的某个数据元素。
(1)查找时插入数据元素。
(2)查找时删除数据元素。
2.2 顺序查找表
顺序查找(Sequential Search)又叫线性查找,是最基本的查找技术,它的查找过程是:从表第一个(或最后一个)记录开始,逐个进行记录的关键字和给定值比较,若某个记录的关键字和给定值相等,则查找成功,找到所查找的记录;如果知道最后一个(或第一个)记录,其关键字和给定值比较都不相等,则表中没有所查的记录,查找不成功。
2.2.1 顺序查找算法
代码实现:
/*顺序查找,a为数组,n为要查找的数组个数,key为要查找的关键字*/ int Sequntial_Search(int *a,int n,int key) { int i; for(i =1;i<=n;i++) { if(a[i]==key) return i; } return 0; }
2.2.2 顺序查找优化
/*有哨兵顺序查找*/ int Sequential_Search2(int *a,int n,int key) { int i; a[0]==key; /*设置a[0]为关键字值,我们称之为“哨兵”*/ i=n; /*循环从数组尾部开始*/ while(a[i]!=key) { i--; } return i; /*返回0则说明查找失败*/ }
时间复杂度为 O(n)。
2.3 有序表查找
2.3.1 折半查找
折半查找(Binary Search)技术,又称为二分查找。它的前提是线性表中的记录必须是关键码有序(通常是从小到大有序),线性表必须采用顺序存储。折半思想:有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等,则查找成功;若给定值小于中间记录的关键字,则在中间记录的左半区继续查找;若给定值大于中间记录的关键字,则在中间记录的右半区继续查找。不断重复上述过程,知道查找成功,或所有查找区域无记录,查找失败为止。
算法实现:
/*折半查找*/ int Binary_Search(int *a,int n,int key) { int low,high,mid; low = 1; /*定义最低下标为记录首位*/ high = n; /*定义最高下标为记录末位*/ while(low<=high) { mid = (low+high)/2; /*折半*/ if(key<a[mid]) /*若查找值比中值小*/ high = mid -1; /*最高下标调整到中位下标小一位*/ else if(key>a[mid]) /*若查找值比中值大*/ low = mid+1; /*最低下标调整到中位下标大一位*/ else return mid; /*若相等则说明mid即为查找到的位置*/ } }
时间复杂度O(logn)。
2.3.2 插值查找
插值查找(Interpolation Search)是根据要查找的关键字key与查找表中最大最小记录的关键字比较厚的查找方法,其核心就在于插枝的计算公式(key-a[low])/(a[high]-a[low])。
mid = low +(high-low)*(key-a[low])/(a[high]-a[low])。
时间复杂度为O(logn),但是对于表长较大,而关键字分布又比较均匀的查找表来说,插枝算法的平均性能比折半查找要好很多。
2.4斐波那契查找
斐波那契数列:
程序运行:
/*斐波那契查找*/ int Fibonacci_Search(int *a,int n,int key) { int low,high,mid,i,k; low = 1; /*定义最低下标为记录首位*/ high = n; /*定义最高下标为记录末尾*/ k = 0; while(n>F[k]-1) /*计算n位于斐波那契数列的位置*/ k++; for(i = n;i<F[k]-1;i++) /*将不满数值补全*/ a[i] = a[n]; while(low<=high) { mid = low +F[k-1]-1; /*计算当前分隔的下标*/ if(key<a[mid]) /*若查找记录小于当前分隔记录*/ { high = mid-1; /*最高下标调整到分隔下标mid-1处*/ k = k-1; /*斐波那契数列下标减一位*/ } else if(key>a[mid]) /*若查找记录大于当前分隔记录*/ { low = mid+1; /*最低下标调整到分隔下标mid+1处*/ k=k-2; /*斐波那契数列下标减两位*/ } else { if(mid<=n) /*若想等说明mid即为查找到得位置*/ return mid; else return n; /*若mid>n说明是补全数值,返回n*/ } } return 0; }
时间复杂度O(logn)。
2.5 线性索引查找
索引就是把一个关键字与它对应的记录相关联的过程。
所谓线性索引就是将索引项集合组织为线性结构,也称为索引表。
2.5.1 稠密索引
在线性索引中,将数据集中的每个记录对应一个索引项。
对于稠密索引这个索引表来说,索引项一定是按照关键码有序的排列。
2.5.2 分块索引
分块有序,是吧数据集的记录分成了若干块,并且:
·快内无序
·块间有序:第二块所有的记录的关键字均大于第一块中所有记录的关键字,第三块的所有记录的关键字均大于第二块的所有记录的关键字。
分块索引的索引项结构分为三个数据项:
·最大关键码,它存储每一块中的最大关键字
·存储了块中的记录个数
·用于指向首数据的指针,便于开始对这一块中记录进行遍历
时间复杂度高于顺序查找,低于折半查找。
2.5.3 倒序索引
索引结构:
·次关键码,例如上面的“英文单词”
·记录号表,例如上面的“文章编号”
其中记录号表存储具有系统次关键字的所有记录的记录号(可以是指向记录的指针或者是该记录的主关键字)。这样的索引方法就是倒序索引(inverted index)。
2.6 二叉树排序
二叉排序树(Binary Sort Tree),又称为二叉查找树。它或者是一棵空树,或者是具有下列性质的二叉树。
·若它的左子树不空,则左子树上所有结点的值均小于它的根结构的值;
·若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
·若它的左,右子树也分别为二叉排序树。
查找实现
/*递归查找二叉排序树T种是否存在key*/ /*指针f指向T的双亲,其初始调用值为NULL*/ /*若查找成功,则指针p指向该数据元素结点,并返回TRUE*/ /*否则指针p指向查找路径上访问的最后一个结点并返回FALSE*/ Status SearchBST(BiTree T,int key,BiTree f,BiTree *p) { if(!T) { *p = f; return FALSE; } else if(key == T->data) { *p = T; return TRUE; } else if(key<T->data) return SearchBST(T->lchild,key,T,p); /*在左子树继续查找*/ else return SearchBST(T->child,key,T,p); /*在右子树继续查找*/ }
3 结语
以上是所有内容,希望对大家有所帮助。