查找
8.2 顺序表
采用顺序存储结构的数据表称为顺序表。顺序表适合作静态查找。
8.2.1 顺序表的查找
基本思想
设有n个数据元素的顺序表,从表的一端(前端或后端)开始,用给定的值依次和表中各数据元素的关键字进行比较,若在表中找到某个数据元素的关键字和给定值相等,则查找成功,给出该数据元素在表中的位置;若查遍整个表,不存在关键字等于给定值的数据元素,则查找失败,给出失败信息。
顺序存储结构下的顺序查找算法
template<class ElemType> int SqSearch(ElemType elem[],int n,ElemType key)
//一般顺序查找比较
{
int i;
for(i=0; i<n && elem[i]!=key ;i++);
if(i<n)
return i;
else
return -1;
}
template<class ElemType> int SqSearch(ElemType elem[],int n)
//使用哨兵elem[0],n的传入的是带上哨兵的长度
{
int i;
for(i=n;elem[i]!=elem[0];i--);
if(i==0)
return -1;
else
return i;
}
- 哨兵优化是对顺序查找的优化,因为每次循环时都需要对i是否越界(i是否小于等于n)作判断。设置一个哨兵,可以解决越界问题。对于查找数字比较大的情况,哨兵的优点更加明显。
- 如果数据元素的数据类型是一个结构体的话,需要在结构体中重载不等于(!=)关系运算。
平均查找长度
- 在等概率(P=1/n)情形下,算法1(不用哨兵)
查找成功的平均查找长度为:ASL=(n-1)/2;
查找失败的平均查找长度为:n+1。 - 在许多情形下数据表中各个数据元素的查找概率是不相等的。这时,可以将数据元素按查找概率的高低,把查找概率高的存放在开始查找的一端,把查找概率低的存放在另一端,从而提高顺序查找的效率。顺序查找的方法比较简单,但查找成功的平均查找长度较长,特别当n较大时查找效率较低。
当然,数据表也可以用链表存储如果顺序表中各个数据元素按关键字从小到大或从大到小有序排列,即为有序表,对有序表进行顺序查找,其查找失败的平均查找长度可减少,因为不需要查遍整个表就能确定表中不存在要找的数据元素。
8.2.2 有序表的折半查找
对有序表通常可用折半查找的方法进行查找。设有n个数据元素按其关键字从小到大的顺序存放在一个顺序表中(开始时,查找区间的下限low-0,上限high=n-1)。
折半查找的算法思想
1)如果查找区间长度小于1(low>high)则表示查找失败,返回-1;否则继续以下步骤。
2)求出查找区间中间位置的数据元素下标mid(mid=(low+high)/2)。
3)用区间中间位置的数据元素的关键字elem[mid]与给定值key进行比较,比较的结果有以下三种可能。
- ①若elem[mid]=key,则查找成功,报告成功信息并返回其下标mid。
- ②若elem[mid]<key,则说明如果数据表中存在要找的数据元素,该数据元素一定在mid的右侧,可把查找区间缩小到数据表的后半部分**(low=mid+1)**,再继续进行折半查找(转步骤1)。
- ③若elem[mid]>key,则说明如果数据表中存在要找的数据元素,该数据元素一定在mid的左侧。可把查找区间缩小到数据表的前半部分**(high=mid-1)**,再维续进行折半查找(转步骤1)。
在折半查找过程中,每比较一次,如果数据元素的关键字和给定值不相等,则查找区间缩小一半。直到查找区间已缩小到只有一个数据元素,如果仍未找到想要找的数据元素,则表示查找失败。
例如,设有序表为{ 8,11,23 34,39,46,68,71,86},下图展示查找关键字为23的数据元素时的查找过程。
折半查找算法
(1)有序表上迭代、递归形式
//递归算法
template<class ElemType> int BinSearch(ElemType elem[],int low,int high,ElemType key)
{
int mid;
if(low>high)
mid=-1;//查找失败
else
{
mid=(low+high)/2;
if(key<elem[mid])//左半边继续查找
mid=BinSearch(elem,low,mid-1,key)