数据结构复习之顺序表查找

基本概念

给定一个值K,在含有n个结点的表中找出关键字等于给定值K的结点

查找表表示

(1)动态查找表和静态查找表
若在查找的同时对表做修改操作(如插入和删除),则相应的表称之为动态查找表。否则称之为静态查找表。
(2)内查找和外查找
若整个查找过程都在内存进行,则称之为内查找;反之,若查找过程中需要访问外存,则称之为外查找。

平均查找长度asl

查找运算的主要操作是关键字的比较,所以通常把查找过程中对关键字需要执行的平均比较次数(也称为平均查找长度)作为衡量一个查找算法效率优劣的标准。
在这里插入图片描述

其中:
① n是结点的个数;
② Ci是找到第i个结点所需进行的比较次数。
③Pi是查找第i个结点的概率.一般认为是等概率的,也就是1/n,顺序查找基本上也就是1/n*(1+2+…+n)=1/n*(n+1)*n/2=(n+1)/2

顺序表查找

数据结构定义

typedef struct {
    KeyType key;
    infoType data;
} NodeType;

typedef NodeType SeqList[n + 1]; //0号单元用作哨兵

一般顺序表的查找算法

int SeqSearch(SeqList R, KeyType k, int n)
{
    //R[0]作为哨兵,用R[0].key==k作为循环下界的终结条件
    R[0].key = k; //设置哨兵
    i = n; //从后向前扫描
    while (R[i].key != k)
        i--;
    return i; //返回其下标,若找不到,返回0
}

算法分析

  • 查找成功:查找成功时的平均查找长度=(1+2+3+…+n)/n=(n+1)/2
  • 查找失败时的查找长度=(n+1)
  • 如果查找成功和不成功机会相等,顺序查找的平均查找长度为((n+1)/2+(n+1))/2= 3/4(n+1)

递增有序查找算法

int SeqSearchl(SeqList R, KeyType k, int n) //有序表的顺序查找算法
{
    int i = n; //从后向前扫描,表按递增排序
    while (R[i].key > k)
        i--; //循环结束时,要么R[i].key=k,要么R[i].key<k
    if (R[i].key == k)
        return i; //找到,返回其下标
    return 0; //没找到,返回O
}

算法分析

  • 查找成功、失败
    (n+1)/2
  • 成功与失败机会均等,平均查找长度也为(n+1)/2

二分查找,必考

前提是有序表

思想

首先将待查的k值和有序表R[1…n]的中间位置mid上的记录(有序表的位置是从1开始,中间位置计算也是1+n /2)的关键字进行比较,若R[mid].key>k,则k在左子表R[1…mid-1]中(中间位置要往前移一位),接着再在左子表中进行二分查找即可。若R[mid].key<k,则说明待查记录在右子表R[mid+l…n](中间位置要往后移一位)中,接着只要在右子表中进行二分查找即可…二分查找的过程是递归的。

算法实现

递归实现
int BinSearch(SeqList R, KeyType k, int low, int high)
{
    //在区间R[low...high]内进行二分递归,查找关键字值等于k的记录
//1ow的初始值为1,high的初始值为n
    int mid;
    if (low <= high) {
        mid = (low + high) / 2;
        if (R[mid].key == k) return mid; //查找成功,返回其下标
        if (R[mid].key > k)
            return BinSearch(R, k, low, mid - 1) ;//在左子表中继续查找
        else
            return BinSearch(R, k, mid + 1, high); //在右子表中继续查找
    } else
        return 0;
}
非递归算法
int BinSearch(SeqLiSt R, KeyType k, int n) //初始化上下界
{
    int low = 1, mid, high = n;
    while (low <= high) {
        mid = (low + high) / 2;
        if (R[mid].key == k)
            return mid; //查找成功,返回其下标
        if (R[mid].key > k)
            high = mid - 1; //修改上界
        else low = mid + 1; //修改下界
    }
    return 0; //查找失败,返回0值
}

算法分析

二分查找方法可以用一棵判定树描述,查找任一元素的过程对应该树中从根结点到相应结点的一条路径。
最短的查找长度为1,最长的查找长度为对应判定树的深度log2n+1,下取整.
平均查找长度为 (n+1)/n log2(n+1)-1≈log2(n+1)-1。
二分查找只适用于顺序结构上的有序表,对链式结构无法进行二分查找。

实例

利用二分查找算法在有序表R中插入一个元素x,并保持表的有序性。

算法实现

void BinInsert(SeqList R, KeyType x, InfoType y, int n)
{
    int low = 1, high = n, mid, inspace, i ;
    int find = 0; //find是作为是否找到与x相等的关键字,先假设未发现
    while (low <= high && ! find) {
        mid = (low + high) / 2;
        if (x < R[mid].key) high = mid - 1;
        else if (x > R[mid].key) low = mid + 1;
        else find = 1;
    }
    if (find)
        inspace = mid; //找到关键字与x相等,mid为x的插入位置
    else
        inspace = low; //所指向的结点关键字正好大于x,此时low即为插入位置
    for (i = n; i >= inspace; i--)
        R[i + 1] = R[i]; //后移结点,留出插入的空位
    R[inspace].key = x; //插入结点,x是该结点的关键字,y是其他数据
    R[inspace].data = y;
}

索引顺序查找

分块查找。它是一种性能介于顺序查找和二分查找之间的查找方法。

索引查找表的存储结构

块内无序,但块间有序

索引表

抽取各块中的最大关键字及其起始位置构成一个索引表

基本思想

(1)首先查找索引表
索引表是有序表,可采用二分查找或顺序查找,以确定待查的结点在哪一块。
(2)然后在已确定的块中进行顺序查找
由于块内无序,只能用顺序查找

查找长度

(1)查找索引表采用二分查找时的平均查找长度
ASLblk=log2(b+1)-1+(s+1)/2≈log2(n/s+1)+s/2
(2)查找索引表采用顺序查找时的平均查找长度

ASLblk=(b+1)/2+(s+1)/2=(b+s)/2+1=(n/s+s)/2+1 =(块数+块长)/2+1

当s取 根号n(即s=b)时, ASLblk 达到最小值 根号n+1,即当采用顺序查找确定块时,应将各块中的结点数选定为 根号n。

三种顺序查找比较

  • 顺序查找
    优点:算法简单,对表的存储结构无任何要求。
    缺点:查找效率低,查找成功的平均查找长度为(n+1)/2,查找失败的查找长度为(n+1)。
  • 二分查找
    优点:二分查找的速度快,效率高,查找成功的平均查找长度约为log2(n+1)-l。
    缺点:要求表以顺序存储表示并且是按关键字有序,使用高效率的排序方法也要花费O(nlog2n)的时间。另外,当对表结点进行插入或删除时,需要移动大量的元素,所以二分查找适用于表不易变动且又经常查找的情况。
  • 分块查找,索引
    优点:在表中插入或删除一个记录时,只要找到该记录所属的块,就可以在该块内进行插入或删除运算。因为块内记录是无序的,所以插入或删除比较容易,无需移动大量记录。
    缺点:是需要增加一个辅助数组的存储空间和将初始表块排序的运算,它也不适宜用链式存储结构。
    此外,顺序查找、二分查找和分块查找三种查找算法的时间复杂度分别为:O(n)、O(log2n)和O(根号n )。
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值