C++数据结构之查找——静态查找表(顺序查找、折半查找、分块查找 带有gif以及图示)

这篇具有很好参考价值的文章主要介绍了C++数据结构之查找——静态查找表(顺序查找、折半查找、分块查找 带有gif以及图示)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、查找的相关概念介绍

1.查找表(Search Table)

概念

对查找表的操作

查找表的分类

2.关键字(Key)

概念

3.查找(Searching)

概念

4.衡量查找算法的标准

1.时间复杂度

2.空间复杂度

3.平均查找长度(ASL)

二、静态查找表

1.顺序查找

算法思路

算法举例

算法性能分析

不等概率

算法特点

算法实现

2.折半查找

算法思路

算法举例

 算法分析

算法实现

3.分块查找

算法介绍

算法思想

算法举例

 算法实现

代码执行结果

三、总结


一、查找的相关概念介绍


1.查找表(Search Table)

概念

查找表是由同一类型的数据元素(或记录)构成的集合

对查找表的操作

1.查询某个特定数据元素是否在查找表种

2.检索某个特定元素的各种属性

3.在查找表中插入一个数据元素

4.从查找表中删除某个数据元素

查找表的分类

1. 静态查找表:仅作查询和检索操作的查找表

2. 动态查找表: 在查找的过程中同时插入查找表中不存在的数据元素或者从查找表中删除已存在的某个数据元素


2.关键字(Key)

概念

关键字是数据元素(或记录)中的某个数据项的值,用来标识(识别)一个数据元素(或记录)

主关键字:可以识别唯一一个记录的关键字

次关键字:能识别若干记录的关键字


3.查找(Searching)

概念

查找是根据某个给定的值在查找表中确定一个其关键字等于给定值的数据元素(或记录)

查找成功:在查找表中查找到指定的数据元素(或记录)

查找失败:在查找表中没有找到指定的数据元素(或记录)


4.衡量查找算法的标准

1.时间复杂度

一个查找算法的时间复杂度越低,说明利用这个查找算法查找到对应关键字的数据元素就越快

2.空间复杂度

一个查找算法的空间复杂度越低,说明这个查找算法占用的内存空间少

3.平均查找长度(ASL)

平均查找长度为确定数据元素(或记录)在表中的位置所进行的和关键字比较的次数的平均值

c++ 查表,数据结构,C++,数据结构,c++,算法

n:查找表的长度,即表中所含元素(或记录)的个数

Pi:查找到第i个元素的概率

Ci:查找第i个元素时,和各个数据元素(或记录)的关键字比较的次数

二、静态查找表


1.顺序查找

算法思路

i.从表中的最后一个数据元素开始

ii.逐个进行数据元素的关键字和给定值进行比较

iii.如果某个数据元素的关键字与给定值比较相等,则查找成功

iv.如果直到第一个数据元素都比较不相等,则查找不成功

算法举例

c++ 查表,数据结构,C++,数据结构,c++,算法

 如上图所示,我们的目标是查找关键字为64的这个数据元素,因此对应的给定值就是64,我们从查找表的表尾开始查找,依次对比关键字,当比对到第7个元素的时候发现64等于第七个元素的关键字64,因此查找成功

算法性能分析

 对于顺序表而言,Ci=n-i+1

 在等概率查找的情况下,Pi=1/n

因此 ASL=n*P1+(n-1)*P2+......+2Pn-1+Pn=(n+1)/2

不等概率

如果被查找的记录概率不等时,取

Pn≥Pn-1≥···≥P2≥P1

若查找概率是无法事先测定的,则查找过程采取的改进方法是,将刚查找到的记录直接移到表尾的位置之上

算法特点

优点:

1.算法简单易实现

2.适应性强,对表结构无任何要求

缺点:

1.ASL(平均查找长度较大)

2.当n很大时,即为大规模数据时,查找的效率很低

算法实现

本算法的实现是基于顺序表的,因此需要先构造一个顺序表,顺序表的实现可以参考我的往期文章

顺序表的实现  当然了也可以用数组来替代,但是关键的不管是用什么结构,首元素不能存放数据,因为首元素的作用是作为哨兵存在的,因此关键数据存储于第二个位置及以后

int sqsearch(sqlist sl,int key)
{
    int searchtime=0;//定义查找次数
    int i=sl.length-1;//得到顺序表的长度
    sl.element[0]=key;//设置哨兵
    while (sl.element[i]!=key)//检查元素
    {
        i--;
    }
    searchtime=sl.length-i;//得到查找次数
    if (i==0)//如果查找到了哨兵说明没查找到对应元素
    {
        return 0;
    }
    return i;//返回查找到的元素下标
}

2.折半查找

算法思路

折半查找是基于有序表的查找方法,因此本算法所处理的数据是经过排序的,算法基本原理如下:

确定待查记录的范围(在前半部分或是后半部分),然后继续确定范围直到找到该元素为止

1.n个对象从小到大存放在有序顺序表ST中,k为给定值
2.设low、high指向待查元素所在区间的下界、上界,即low=1, high=n
3.设mid指向待查区间的中点,即mid=(low+high)/2
4.让k与mid指向的记录比较
  若k<ST[mid].key,则high=mid-1    [上半区间]
  若k>ST[mid].key,则low=mid+1        [下半区间]
5.重复3,4操作,直至low>high时,查找失败

算法举例

c++ 查表,数据结构,C++,数据结构,c++,算法

 算法分析

判定树

我们先不管要查找的Key是什么,我们将查找的整个过程中检查element[mid]的顺序列出来,我们就可以得到一颗描述查找过程的二叉树,我们称之为判定树,如下图所示:

c++ 查表,数据结构,C++,数据结构,c++,算法

 设我们有这么一个表,我们对其得到其的判定树:

c++ 查表,数据结构,C++,数据结构,c++,算法

性能分析(查找成功bs与查找失败bsf)

tips:以下的所有log都表示的是以2为底数的对数

我们可以知道,一个二叉树的每一层的节点最多有2^(i-1)个节点(i为层数),因此对于一个k层的二叉树,我们一共有:

c++ 查表,数据结构,C++,数据结构,c++,算法

 共2^k-1个节点,,因此有n个结点的判定树的深度为k=log(n+1),因此折半查找法在查找过程中进行的比较次数最多不超过log(n+1)。设有序表的长度n=2^h-1(即h=log (n+1)),则描述折半查找的判定树是深度为h的满二叉树,树中层次为1的结点有1个,层次为2的结点有2个,层次为h的结点有2^(h-1)个,假设表中每个记录的查找概率相等,则查找成功时折半查找的平均查找长度:

c++ 查表,数据结构,C++,数据结构,c++,算法

我们来对折半算法的ASL进行解析:首先我们对ASL的概念进行回顾

c++ 查表,数据结构,C++,数据结构,c++,算法

 因为查找概率相等,因此Pi=1/n,我们将其从式子中提出来就得到了:

c++ 查表,数据结构,C++,数据结构,c++,算法

 我们再对Ci的概念进行回顾:

c++ 查表,数据结构,C++,数据结构,c++,算法

 我们可以知道,我们现在对元素的检查已经不再是像顺序查找一样一个一个进行检查了,而是像一颗树一样进行检查,且根据我们所选择的Key不同,每次从树的顶端开始走的路径都不同,且一次走一层,因此我们就可以把查找第i个元素时同给定值Key比较的次数转换为查找第j层元素时同给定值Key比较的次数,我们可以知道一个深度为h的树每层有2^(j-1)个节点,每个节点的上面都有j层,因此Ci就等于 j x 2^(j-1),我们代入ASL计算公式后就可以得到:

c++ 查表,数据结构,C++,数据结构,c++,算法

 当我们查找失败的时候,也就是说我们查找到了判定树的最后一层的下一层,对此要具体例子具体计算,我在下面贴出一篇我觉得写的不错的文章,有兴趣的可以继续对ASL的计算进行了解:

ASL平均查找长度(查找失败与查找成功时的ASL计算)https://blog.csdn.net/weixin_38233103/article/details/109248616?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166314104016782391812654%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=166314104016782391812654&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~hot_rank-4-109248616-null-null.142%5Ev47%5Econtrol_1,201%5Ev3%5Econtrol_2&utm_term=%E6%8A%98%E5%8D%8A%E6%9F%A5%E6%89%BE%E7%9A%84%E5%B9%B3%E5%9D%87%E6%9F%A5%E6%89%BE%E9%95%BF%E5%BA%A6&spm=1018.2226.3001.4187

算法实现

int binarysearch(sqlist sl,int key)
{
    int left,mid,right ;
    left=0;//初始化三个标志位
    right=sl.length-1;
    mid=(left+right)/2;
    while (sl.element[mid]!=key)//当未查找到时就一直进行查找
    {
        if(left<=right)//当left<=right意味着还能继续查找 
        {
            if (key>sl.element[mid])
            {
                left=mid+1;
                mid=(left+right)/2;
            }
            else
            {
                right=mid-1;
                mid=(left+right)/2;
            }
                
        }
        else//当left>right说明已经越界了,也代表着查找失败
        {
            cout<<"查找失败!"<<endl;
            break;
        } 
    }
    if (sl.element[mid]==key)//最后对结果进行检查并返回对应值
    {
        cout<<"查找成功!"<<endl;
        return mid;
    }
    else
    {
        return -1;//查找失败就返回-1
    }      
}

3.分块查找

算法介绍

分块查找是一种索引顺序表(分块有序表)查找方法,索引顺序表(分块有序表)将整个表分成几块,块内无序,块间有序,所谓块间有序是指后一块表中所有记录的关键字均大于前一块表中的最大关键字

分块查找包含两个表:分别是主表和索引表

主表:用数组存放待查记录,每个数据元素包含关键字
索引表:用链表存放每个结点,每个节点含有本块的最大关键字和本块第一个结点下标

算法思想

1.我们将所有元素放入数组中,我们称之为主表

2.我们由数组的长度length来自己规定块长n,得到索引表的长度为length/n

3.我们对每个块进行遍历找出最大关键字,并将该块的首元素下标与最大关键字存入索引表中

4.以此类推直到所有块被操作完毕

5.我们对索引表按照最大关键字的大小进行排序

6.然后我们利用顺序查找对索引表进行操作

7.找到不小于key值得块我们对该块进行顺序查找我们的key

8.找不到我们就对下一个块进行顺序查找来找我们的key

9.以此类推直到查找到key或查找失败

算法举例

         我们将一组数据存入主表,我们根据数据的数量11,我们设定分块长度为4,由此我们可以得到索引表的长度为11/4=3,然后我们对主表进行分块,得到三块,将每块的首元素索引以及最大关键字存储入索引表中并对索引表依据最大关键字进行排序就得到了下图:

c++ 查表,数据结构,C++,数据结构,c++,算法

 采用折半查找方法在索引表中找到块[第2块],用顺序查找方法在主表对应块中找到和key值对应的元素,即第三元素,我们返回这个元素的下标作为查找结果

c++ 查表,数据结构,C++,数据结构,c++,算法

 算法实现

链表类及链表相关操作

class node
{
    public:
    int maxkey;
    int firstindex;
    node *next;

};
//创建链表,因为创建一个链表一定要有一个头节点,这个头节点是没有数据的
node* createlist()
{
    node* head=(node*)calloc(1,sizeof(node));//使用calloc为指针分配内存
    if(head==NULL)//并且要注意,在c++中,calloc和malloc返回的是void,因此要通过q‘强制转换才能继续使用
    {
        return NULL;
    }
    return head;
}
//创建节点
node* createnode(int maxkey,int firstindex)
{
    node* newnode=(node*)calloc(1,sizeof(node));
    if(newnode==NULL)
    {
        return NULL;
    }
    newnode->maxkey=maxkey;
    newnode->firstindex=firstindex;
    return newnode;
}
//添加元素:把数据从尾部插入
void pushback(node *head,int maxkey,int firstindex)
{
    node* newnode=createnode(maxkey,firstindex);
    node* curnode=head;
    while(curnode->next!=NULL)
    {
        curnode=curnode->next;
    }
    //插入数据
    curnode->next=newnode;
}

void print(node*head)
{
    node* curnode=head->next;
    while (true)
    {
        if(curnode->next!=NULL)
        {
            cout<<"当前节点maxkey:"<<curnode->maxkey<<" 当前节点firstindex:"<<curnode->firstindex<<endl;
            curnode=curnode->next;
        }
        else
        {
            cout<<"当前节点maxkey:"<<curnode->maxkey<<" 当前节点firstindex:"<<curnode->firstindex<<endl;
            break;
        }
    }  
}

node* find(node* list,int num)
{
    node* ptr=list;
    for (int i = 0; i < num; i++)
    {
        ptr=ptr->next;  
    }
    return ptr;
    
}

 分块查找

int blocksearch(int arr[],int arrlength,int key)
{
    //创建索引表
    node* list=createlist();
    //得到索引表
    cout<<"数组的长度为:"<<arrlength<<" 请输入块长:"<<endl;
    float blocklength;
    cin>>blocklength;
    float blocknumber1=arrlength/blocklength;
    int blocknumber2=arrlength/blocklength;
    int blocknumber;
    blocknumber=blocknumber1>blocknumber2?blocknumber2+1:blocknumber2; 
    int sllength=arrlength;
    int start=0;
    int length;
    for (int i = 1; i <=blocknumber; i++)
    {
        int max=0;
        sllength-=blocklength;
        //cout<<"当前sllength:"<<sllength<<endl;
        if (arrlength>blocklength)
        {
            length=blocklength;
        }
        else
        {
            length=sllength;
        }
        //cout<<"当前start:"<<start<<endl;
        //cout<<"当前length:"<<length<<endl;
        for (int j = start; j < start+length; j++)
        {
            if (arr[j]>max)
            {
                max=arr[j];
            }
            
        }
        //cout<<"索引表加入start:"<<start<<" max:"<<max<<endl;
        pushback(list,max,start);
        start+=blocklength;
    }
    //打印索引表
    cout<<"===============索引表================"<<endl;
    print(list);
    cout<<"===================================="<<endl;
    cout<<endl;
    //建新表对索引表进行排序
    node* newlist=createlist();
    node *curnode=list->next;
    cout<<"一共有"<<blocknumber<<"个块"<<endl;
    for (int j = 0; j < blocknumber; j++)
    {
        int min=999;
        int mini=0;
        int i=0;
        int temp;
        while (curnode->next!=NULL)
        {
            i++;
            //cout<<"curnode的maxkey为:"<<curnode->maxkey<<endl;
            if (curnode->maxkey<min)
            {
                min=curnode->maxkey;
                mini=curnode->firstindex;
                temp=i;
            }
            //cout<<"curnode"<<curnode->maxkey<<"变为"<<curnode->next->maxkey<<endl;
            curnode=curnode->next;
        }
        //最后一个节点还要再操作一遍
        i++;
         //cout<<"curnode的maxkey为:"<<curnode->maxkey<<endl;
        if (curnode->maxkey<min)
        {
            min=curnode->maxkey;
            mini=curnode->firstindex;
            temp=i;
        }
        node* ptr=list;
        for (int k = 0; k < temp; k++)
        {
            ptr=ptr->next;
        }
        cout<<"找到的最小node的maxkey为:"<<ptr->maxkey<<endl;
        ptr->maxkey=1000;
        curnode=list->next;
        pushback(newlist,min,mini);
        //cout<<"索引表加入min:"<<min<<" mini:"<<mini<<endl;
        //cout<<"当前索引表最小maxkey为:"<<min<<endl;
    }
    //打印新索引表
    cout<<"===============新索引表================"<<endl;
    print(newlist);
    cout<<"===================================="<<endl;
    cout<<endl;
    
    //对新索引表进行顺序查找
    int startindex=1;
    while (startindex<=blocknumber)
    {

        int target= find(newlist,startindex)->firstindex;
        for (int i = target; i < target+blocklength; i++)
        {
            if (key==arr[i])
            {
                return i;//查找到并返回下标
            }
                
        }
        startindex++;
    }
    return -1;//未查找到
}

main函数

int main()
{
    cout<<"请输入数组长度:"<<endl;
    int arrlength;
    cin>>arrlength;
    int arr[arrlength];
    for (int i = 0; i < arrlength; i++)
    {
        cout<<"请输入arr["<<i<<"]:";
        cin>>arr[i];
    }
    cout<<"请输入key值:"<<endl;
    int key;
    cin>>key;
    blocksearch(arr,arrlength,key);
    return 0;
}

代码执行结果

c++ 查表,数据结构,C++,数据结构,c++,算法

 

三、总结

本文对查找进行了介绍,并且有对ASL平均查找长度进行讲解和举例计算,重点为三种算法的介绍和实现,其中顺序查找作为最基本的查找算法是一定要掌握的,折半查找作为效率最高的算法尤其应该予以重视,分块查找是介于顺序查找和折半查找效率的一个算法,实现起来较麻烦,但是也需要掌握,如果喜欢本文的话希望可以点一个赞,你的肯定是我进步的动力!!!

👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍👍文章来源地址https://www.toymoban.com/news/detail-774975.html

到了这里,关于C++数据结构之查找——静态查找表(顺序查找、折半查找、分块查找 带有gif以及图示)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 头歌(C语言)-数据结构与算法-查找-第1关:实现折半查找

    任务描述 相关知识 编程要求 测试说明 任务描述 本关要求通过补全函数 BSL_FindKey 来实现在已排序的顺序表中查找关键码值为 key 的结点并返回该结点的编号。 相关知识 折半查找通常是针对顺序存储的线性表,线性表的结点按关键码从小到大排序,后面称之为折半查找的顺序

    2024年02月10日
    浏览(40)
  • 数据结构算法--1 顺序查找二分查找

    顺序查找时间复杂度为O(n) 我们可以借助Python中的函数enumerate,通过enumerate遍历列表返回其索引和值 也可以通过列表长度依次遍历: 但是二分查找时间复杂度为O(logn):

    2024年02月12日
    浏览(38)
  • 数据结构之顺序查找

    ​ 活动地址:CSDN21天学习挑战赛 目录 数据结构概念: 算法效率: 1)时间复杂度 2)空间复杂度 顺序查找: 代码实现:    作者简介:大家好我是小唐同学(๑؂๑),大家可以叫我小唐 个人主页: 小唐同学(๑؂๑)的博客主页 系列专栏:数据结构 博友们如果也是新手入

    2024年02月13日
    浏览(44)
  • 数据结构--顺序表的查找

    目标: GetElem(L,i):按位查找操作。获取表L中第i个位置的元素的值。 代码实现 时间复杂度 O(1) 由于顺序表的各个数据元素在内存中连续存放,因此可以根据起始地址和数据元素大小立即找到第i个元素——“随机存取”特性 目标: LocateElem(Le):按值查找操作。在表L中查找具有给

    2024年02月11日
    浏览(37)
  • 数据结构与算法之查找: 顺序查找 (Javascript版)

    顺序查找 思路 遍历数组 找到跟目标值相等元素,就返回它的下标 没有找到,返回-1 算法实现 总结 非常低效,算是入门搜索 时间复杂度:O(n) 对于数组结构或链表结构而言,没什么太多可说的

    2024年02月05日
    浏览(37)
  • 数据结构-查找(顺序查找与二分查找的讲解与代码实现)

    顺序查找概念:从表的另一端开始,一次将记录的和给定值进行比较,若某个记录的和给定的值相等,则查找成功,反之则查找失败。 ASL:平均查找长度 pi查找概率,ci查找次数 eg:序列1,2,3 查找1的次数为1概率为1/3,2为两次概率1/3,3的次数为3概率1/3  将12

    2024年02月06日
    浏览(58)
  • 数据结构--6.3查找算法(静态、动态)(插值查找)

    静态查找:数据集合稳定,不需要添加,删除元素的查找操作。 动态查找:数据集合在查找的过程中需要同时添加或删除元素的查找操作。 对于静态查找来说,我们不妨可以用线性表结构组织数据,这样可以使用顺序查找算法,如果我们在对进行排序,则可以使用折

    2024年02月09日
    浏览(28)
  • 【数据结构】顺序表的实现——静态分配

    🎈个人主页:豌豆射手^ 🎉欢迎 👍点赞✍评论⭐收藏 🤗收录专栏:数据结构 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 在数据结构的领域中,顺序表是一种基础且重要的线性表实现方式。它采用一段地址连续的存储

    2024年04月26日
    浏览(27)
  • 【数据结构】静态分配的顺序表插入元素

    分析一下当前算法的时间复杂度,注意:顺序表的元素移动,是从最后一个元素依次移动的 1、新元素插入到表尾,i=n+1,就不用移动元素,不移动就不要走for循环,for循环0次,时间复杂度为O(1) 2、新元素插入到表头,i=1,就要移动所有元素,有n个元素移动n个,for循环n次,

    2024年02月07日
    浏览(27)
  • C语言--顺序查找、折半查找

    顺序查找(sequential search)就是按照 数组 的顺序一 一比较数组中的元素的值和所查找的值。如下图表所示,遍历数组进行比较。若找到,则break跳出循环。 a[0] a[1] a[2] a[3] a[4] 9 12 22 13 34 22==9? 22==12? 22==22?              折半搜索(英语:half-interval search),也称二分搜索、

    2024年02月07日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包