《数据结构》实验报告七:查找

这篇具有很好参考价值的文章主要介绍了《数据结构》实验报告七:查找。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实验目的

1、掌握查找表动态查找表静态查找表平均查找长度的概念。

2、掌握线性表中顺序查找折半查找的方法。

3、学会哈希函数的构造方法,处理冲突的机制以及哈希表的查找

二、实验预习 

说明以下概念

1、顺序查找:

        顺序查找又叫线性查找,是最基本的查找方法。

        查找思路:查找表的第一个(或最后一个数据元素开始,逐个将数据元素的关键字和给定的关键字进行比较,如果存在某个数据元素的关键字和给定关键字相等则查找成功,返回该数据元素相关信息;如果直到最后一个(或第一个)数据元素还未找到和给定关键字相等的数据元素,则查找失败,表中没有所查的数据。

2、折半查找:

        折半查找也叫二分查找、对分查找。折半查找的前提是查找表中所有数据元素的关键字按照递增或递减有序排列

        查找思路:假设查找表中数据元素关键字按照递增有序排列,设置一个指针 low 指向查找表中关键字最小的位置,设置一个指针 high 指向查找表中关键字最大的位置,再设置一个指针 mid 指向查找表中间位置。

        ① mid=(low+high)/2。

        ② 将给定的关键字 k 与 mid 位置的关键字 m 比较:

             若k=m,查找成功,返回相关数据元素信息。

             若k<m,则high=mid-1,重复以上操作(从①开始)

             若k>m,则low=mid+1,重复以上操作(从①开始)

        ③ 如果直至 low>high 还未查找成功,则查找失败。

3、哈希函数:

        哈希函数又叫散列函数、杂凑函数,是散列方法中使用的转换函数

        在使用散列方法存储查找表中的数据元素时,选取一个函数,依照该函数和关键字计算数据元素的存储位置,并按此位置存放,这个函数就是哈希函数

        同样的,在查找时,由同一个哈希函数对给定的关键字 k 进行计算得到地址,再将 k 与该地址中数据元素的关键字进行比较,确认是否查找成功。

        哈希函数就是记录的存储位置与关键字之间的对应关系Loc(element.i)=Hash(key.i)

4、冲突及处理:

        冲突就是在散列表中使用哈希函数,根据关键字计算存储地址时,不同的关键码映射到了同一个散列地址,这些具有相同函数值的多个关键字叫做同义词

        处理方法:开放地址法、链地址法、再散列法、建立一个公共溢出区……

(1)开放地址法(开地址法)

基本思想:发生冲突时就寻找下一个空的散列地址(即地址加上某个增量),若找到空地址,则将数据存入。

例如:除留余数法 Hi=( Hash(key)+di )mod m ,di为增量序列(m为查找表中元素个数)

开放地址法寻找空地址常用方法:

① 线性探测法:di为1,2,3,……,m-1 的线性序列

② 二次探测法:di为1*1,- 1*1,2*2,- 2*2,……,q*q 的二次序列

③伪随机探测法:di为伪随机数序列。

(2)链地址法(拉链法)

基本思想:相同散列地址(同义词)的数据元素链成一个单链表,m个散列地址就设置m个单链表,然后用一个数组存储m个单链表的表头指针,形成一个动态的结构。

        根据数据元素的关键字计算散列函数值(即地址),若该地址对应的链表为空,则该地址直接存储该数据元素结点;若该地址对应的链表非空,则将该元素插入此链表(前插法/后插法)。

三、实验内容和要求

1. 静态查找表技术

        依据顺序查找算法和折半查找算法的特点,对下面的两个查找表选择一个合适的算法,设计出完整的C源程序,并完成问题:

查找表1:{ 8,15,19,26,33,41,47,52,64,90 },查找key = 41

查找表2:{12,76,29,15,62,35,33,89,48,20 },查找key = 35

查找 key=41 的算法:  折半查找法                  比较次数:  3  

查找 key=35 的算法:  顺序查找法                  比较次数:  5  

选择依据:可以看出查找表1中的数据是按递增有序排列的,所以可以选择折半查找法;而查找表2中的数据是无序的,看不出什么规律,所以选择顺序查找法。

  • 顺序查找算法实现代码
#include <stdio.h>
#define MAX_NUM 50   //查找表中数据元素最大数量

typedef struct{
    int key;   //关键字域
}ElemType;     //定义数据元素类型

typedef struct{
    ElemType elem[MAX_NUM];  //从下标为1的分量开始存储(0位置设置监视哨)
    int length;              //表长
}SST;                        //Sequence Search Table-顺序查找表

/*顺序查找算法,ST为目标查找表,key为给定的关键字*/
int Seq_Search(SST ST,int key)
{
    ST.elem[0].key = key;   //设置监视哨
    int i;
    for(i=ST.length;ST.elem[i].key != key;i--)
    {
        ;   //for循环内为空语句
    }
    return i;   //返回0:查找失败;返回值>0:查找成功
}

int main()
{
    int i,n,key;
    printf("请输入查找表中记录个数n:\n");
    scanf("%d",&n);
    SST ST;
    ST.length = n;
    printf("\n请输入查找表中数据记录:\n");
    for(i=1;i<ST.length+1;i++)
        scanf("%d",&(ST.elem[i].key));
    printf("\n请输入查找的关键字key:\n");
    scanf("%d",&key);

    /*顺序查找*/
    int m = Seq_Search(ST,key);
    if( m )
        printf("\n查找成功!该记录的位置为:%d",m);
    else
        printf("\n查找失败!查找表中没有该记录");
    return 0;
}
  • 运行结果:

《数据结构》实验报告七:查找

  • 折半查找算法实现代码
#include <stdio.h>
#define MAX_NUM 50   //查找表中数据元素最大数量

typedef struct{
    int key;   //关键字域
}ElemType;     //定义数据元素类型

typedef struct{
    ElemType elem[MAX_NUM];  //从下标为1的分量开始存储(0位置设置监视哨)
    int length;              //表长
}SST;                        //Sequence Search Table-顺序查找表

/*折半查找算法,ST为目标查找表,key为给定的关键字*/
int Bin_Search(SST ST,int key)
{
    int low = 1;
    int high = ST.length;
    int mid;
    while(low <= high)
    {
        mid = (low+high)/2;
        if(key == ST.elem[mid].key)
            return mid;
        if(key < ST.elem[mid].key)
            high = mid - 1;
        if(key > ST.elem[mid].key)
            low = mid + 1;
    }
    return 0;  //返回0:查找失败;返回值>0:查找成功
}

/*折半查找的递归算法*/
//ST为目标查找表,key为给定的关键字,low为查找区间的开始下标,high为查找区间的结束下标,*/
int Bin_Search_R(SST ST,int key,int low,int high)
{
    if(low > high)
        return 0;   //查找失败

    int mid;
    mid = (low+high)/2;

    if(key == ST.elem[mid].key)
        return mid;

    if(key < ST.elem[mid].key)
        Bin_Search_R(ST,key,low,high-1);

    if(key > ST.elem[mid].key)
        Bin_Search_R(ST,key,low+1,high);
}

int main()
{
    int i,n,key;
    printf("请输入查找表中记录个数n:\n");
    scanf("%d",&n);
    SST ST;
    ST.length = n;
    printf("\n请输入查找表中数据记录:\n");
    for(i=1;i<ST.length+1;i++)
        scanf("%d",&(ST.elem[i].key));
    printf("\n请输入查找的关键字key:\n");
    scanf("%d",&key);

    /*折半查找*/
    int m = Bin_Search(ST,key);
    if( m )
        printf("\n折半查找:\n查找成功!该记录的位置为:%d",m);
    else
        printf("\n折半查找:\n查找失败!查找表中没有该记录");

    /*折半查找-递归版*/
    int k = Bin_Search_R(ST,key,1,ST.length);
    if( k )
        printf("\n折半查找(递归算法):\n查找成功!该记录的位置为:%d",k);
    else
        printf("\n折半查找(递归算法):\n查找失败!查找表中没有该记录");
    return 0;
}
  • 运行结果:

《数据结构》实验报告七:查找

2. 哈希表的构造与查找。

【注】

以下代码中SearchHash函数中while循环的条件,和老师给的代码略有不同,包括网上有些代码也是有一点问题的,构造哈希表时可能会出错。

/*采用开放地址法构造哈希表*/
#include<stdio.h>
#include<malloc.h>

#define MAXSIZE 25  //哈希表中元素最大数目
#define P 13        //除留余数法的除数
#define OK 1
#define ERROR 0
#define DUPLICATE -1
#define TRUE 1
#define FALSE 0

typedef struct{
    int key;  /*关键字值*/
    int flag; /*是否存放元素*/
}ElemType;    /*哈希表元素结构*/

typedef struct{
    ElemType data[MAXSIZE];
    int count;      /*元素个数*/
    int sizeindex;  /*当前哈希表容量*/
}HashTable;         /*哈希表*/

int d1[15]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};                           /*线性探测序列*/
int d2[15]={0,1,-1,2*2,-2*2,3*3,-3*3,4*4,-4*4,5*5,-5*5,6*6,-6*6,7*7,-7*7}; /*二次探测序列*/

void dataset(int ds[],int *len);                       /*输入查找表*/
int InsertHash(HashTable *H,int e,int d[]);            /*计算哈希地址,插入哈希表*/
int CreateHash(HashTable *H,int ds[],int len,int d[]); /*构造哈希表*/
int SearchHash(HashTable *H, int e,int d[]);           /*在哈希表中查找*/
void menu();                                           /*演示菜单*/

/*输入查找表*/
void dataset(int ds[],int *len){  //查找表关键字通过ds数组返回,查找表长度通过指针len返回
    int n,m;
    n = 0;
    printf("\n查找表输入(输入一个非整数结束):");
    //scanf()返回值表示正确输入参数的个数
    while(scanf("%d",&m) == 1)  /*以输入一个非整数作为结束*/
    {
        ds[n]=m;  //ds数组存放查找表关键字
        n++;      //n记录个数
    }
    *len=n;
}

/*计算哈希地址,插入哈希表*/
int InsertHash(HashTable *H,int e,int d[]){  //H为目标哈希表,e为插入的关键字,d数组指向线性或二次探测序列
    int k,i=1;
    k = e%P;   //除留余数法计算地址
    while(H->data[k].flag==TRUE || k<0)  //发生冲突or计算得到的位置<0
    {
        k = (e%P+d[i])%MAXSIZE;
        i++;
        if(i>=15)
            return ERROR;                //探测序列所有值都尝试后仍未找到合适地址,则插入失败,返回0
    }

    //成功找到空地址
    H->data[k].key = e;
    H->data[k].flag = TRUE;
    H->count++;  //插入成功,哈希表长度+1
    return OK;   //返回1
}

/*构造哈希表*/
int CreateHash(HashTable *H,int ds[],int len,int d[]){  //ds数组存放查找表的关键字,len为记录个数,d数组指向线性或二次探测序列
    int i;
    for(i=0;i<len;i++)
    {
        if(SearchHash(H,ds[i],d) != -1)
            return DUPLICATE;            //查找成功,说哈希表中已存在该关键字,故创建失败,返回-1

        //查找失败,说明不存在重复关键字,可以插入
        InsertHash(H,ds[i],d);
        if(H->count >= MAXSIZE)
            return ERROR;                //记录个数超过MAXSIZE,返回0
    }
    return OK;                           //创建成功,返回1
}

/*初始化哈希表*/
void InitHash(HashTable *H){
    int i;
    for(i=0;i<MAXSIZE;i++)
    {
        H->data[i].key = 0;
        H->data[i].flag = FALSE;
    }
}

/*在哈希表中查找*/
int SearchHash(HashTable *H,int e,int d[]){  //e为查找的关键字,d数组指向线性或二次探测序列(查找和插入应使用同一个探测序列)
    int k,i=1;
    k = e%P;
    while(H->data[k].key!=e || k<0)
    {
        k = (e%P+d[i])%MAXSIZE;
        i++;
        if(i>=15)
            return -1;  //探测序列中所有值都尝试过仍未找到关键字e,说明哈希表中不存在该关键字,查找失败,返回-1
    }
    return k;           //查找成功,返回该关键字在哈希表中的位置
}

/*演示菜单*/
void menu(){
    int choice;
    int *p;
    HashTable h;
    h.count=0;
    h.sizeindex = MAXSIZE;
    int a[MAXSIZE]={0};
    int i,n,e;
    dataset(a,&n);  /*建立查找表*/
    getchar();      //消耗回车键
    printf("\n");
    do{
        printf("\n----哈希查找演示----\n");
        printf("\n1.线性探测构造哈希表\n");
        printf("\n2.二分探测构造哈希表\n");
        printf("\n3.退出\n");
        printf("\n输入选择:");
        scanf("%d",&choice);
        if(choice == 1)
            p = d1;                //p指向线性探测序列
        else if(choice == 2)
            p = d2;                //p指向二次探测序列
        else
            return;
        InitHash(&h);              /*初始化哈希表*/

        i = CreateHash(&h,a,n,p);  /*构造哈希表*/
        if( !i )
            printf("\n哈希表构造失败!\n");

        else if(i == DUPLICATE)
            printf("\n哈希表具有重复关键字!\n");
        else
        {
            printf("\n哈希表:\n");
            for(i=0;i<h.sizeindex;i++)
                printf("%3d",h.data[i].key);
            printf("\n\n哈希查找\n输入要查找的key值:");
            getchar();   //消耗回车键
            scanf("%d",&e);
            if((i=SearchHash(&h,e,p)) == -1)
                printf("\n%d未找到\n",e);
            else
                printf("\n%d在哈希表中下标为%d\n",e,i);
        }
        getchar();
    }while(1);
}

int main()
{
    menu();
    return 0;
}

输入查找表为:19 14 23 1 68 20 84 27 55 11 10 79(注意以输入一个非整数结束)。

  • 运行结果

1)线性探测散列

哈希表形态:

《数据结构》实验报告七:查找

84在哈希表中的位置:  

2)二次探测散列

哈希表形态:

《数据结构》实验报告七:查找

84在哈希表中的位置:  

我开始是直接运行老师给的代码,输入选择2,通过二分探测法构造哈希表,却得到以下结果: 

哈希表具有重复关键字!

《数据结构》实验报告七:查找

        但是通过线性探测法构造却是正常的,也很容易看出输入的数据是没有重复的。那为什么会显示有重复的关键字呢?

        先来到打印 “哈希表具有重复关键字!”语句的代码:

i = CreateHash(&h,a,n,p);  /*构造哈希表*/
……
else if(i == DUPLICATE)  //DUPLICATE=-1
    printf("\n哈希表具有重复关键字!\n");

        说明CreateHash函数返回了-1,而CreateHash函数返回-1则是因为SearchHash函数返回了一个不等于-1的数。

        所以我在原来的SearchHash函数里添加了一行代码,如果查找成功、就输出重复关键字的信息:

int SearchHash(HashTable *H,int e,int d[]){
    ……
    while(H->data[k].key!=e)
    {
       ……
    }
    printf("重复关键字:%d,在哈希表中下标为:%d",H->data[k].key,k);  //添加代码
    return k;           //查找成功,返回该关键字在哈希表中的位置
}

运行后得到以下结果:

《数据结构》实验报告七:查找

        容易看出 68 在查找表中是没有重复的,但是却显示重复,而且下标还是个负数,哈希表的下标范围应该是 0 ~ MAXSIZE-1,所以负数下标指示的关键字不属于哈希表

        那为什么会查找到哈希表以外的数据呢?因为在插入关键字和查找关键字时哈希地址的计算没有统一。

InsertHash函数中,对地址 k 是有限制的:当计算出的地址 k<0 时,需要重新计算地址。

k=e%P;
while(H->data[k].flag==TRUE || k<0){
    k=(e%P+d[i])%MAXSIZE;

    i++;
    if(i>=15)
        return ERROR;
}

原SearchHash函数中,却没有对地址 k 进行限制,没有判断地址 k 的值是否超过哈希表范围。而二次探测序列中存在负数,且增量跨度较大,地址很可能会超出范围。

k = e%P;

while(H->data[k].key!=e){ 
    k=(e%P+d[i])%MAXSIZE;i++;
    if(i>=15)
        return -1;
}

  • 解决方法: 

插入关键字和查找关键字计算地址时时,不仅使用的哈希函数要相同其它限制条件也要相同

所以这里直接在查找时增加一个和插入操作相同的条件即可,即地址k<0时,重新计算地址。

int SearchHash(HashTable *H,int e,int d[]){ 
    ……
    k = e%P;
    while(H->data[k].key!=e || k<0)
    {
        k = (e%P+d[i])%MAXSIZE;
        i++;
        if(i>=15)
            return -1;  
    }
    return k;           //查找成功,返回该关键字在哈希表中的位置
}文章来源地址https://www.toymoban.com/news/detail-461675.html

到了这里,关于《数据结构》实验报告七:查找的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 《数据结构》实验报告二:顺序表 链表

    1、掌握线性表中元素的 前驱、后续 的概念。 2、掌握顺序表与链表的 建立 、 插入 元素、 删除 表中某元素的算法。 3、对线性表相应算法的 时间复杂度 进行分析。 4、理解顺序表、链表数据结构的特点( 优缺点 )。 说明以下概念 1、线性表:         具有 相同特性 的数

    2024年02月08日
    浏览(43)
  • 图的最短路径 (数据结构实验报告)

    一、实验目的 讲清楚进行本实验后要学到的知识、掌握的数据结构及其定义和表示方法,讲清楚所采用的算法。 掌握图结构的(邻接矩阵)输入方法 掌握图结构的说明、创建以及图的存储表示(邻接矩阵) 掌握最短路径算法原理 掌握最短路径算法的编程实现方法 二、实验

    2024年02月06日
    浏览(49)
  • 《数据结构》实验报告六:图的表示与遍历

    1、掌握图的 邻接矩阵 和 邻接表 表示 2、掌握图的 深度优先 和 广度优先 搜索方法 3、理解 图的应用 方法 说明以下概念 1、深度优先搜索遍历:        一种图的遍历方式:从图中 任意一个 起始顶点 V 出发,接着访问它的任意一个 邻接顶点 W1 ;再从 W1 出发,访问与 W1

    2024年02月06日
    浏览(59)
  • 数据结构实验报告(三)——图的操作和实现

    1.掌握图的基本概念、性质与应用问题 2.掌握图的邻接矩阵与邻接表存储方式; 3.掌握图的有关算法,如创建、遍历、连通分量、生成树/最小生成树算法(如Prim、Kruskal算法)等; 1.建立与存储 邻接矩阵:采用二维数组来存储顶点之间的相邻关系,若两个顶点之间有直连边

    2024年02月06日
    浏览(55)
  • 数据结构“基于哈夫曼树的数据压缩算法”的实验报告

    一个不知名大学生,江湖人称菜狗 original author: jacky Li Email : 3435673055@qq.com Last edited: 2022.11.20 目录 数据结构“基于哈夫曼树的数据压缩算法”的实验报告 一、实验目的 二、实验设备 三、实验内容 1.【问题描述】 2.【输入要求】 3.【输出要求】 4.【实验提示】 四、实验步骤

    2024年02月09日
    浏览(62)
  • 数据结构实验报告,二叉树的基本操作(C语言)

    作者:命运之光 专栏:数据结构 实验六 二叉树的基本操作 实验环境:Visual C++或Dev C++ 实验目的: 1、掌握二叉树创建; 2、掌握二叉树的遍历及常用算法。 实验内容: 通过完全前序序列创建一棵二叉树,完成如下功能: 1)输出二叉树的前序遍历序列; 2)输出二叉树的中序遍

    2024年02月09日
    浏览(37)
  • 《数据结构》实验报告四:串的模式匹配(BF算法、KMP算法)

    1、了解 串 的基本概念。 2、掌握 串的模式匹配算法 的实现 。 说明以下概念 1、模式匹配:          串的模式匹配就是 子串的定位运算 。          设有两个字符串 S 和 T ,S为 主串(正文串) ,T为 子串(模式串) 。在主串S中查找与模式串T相匹配的子串,若匹配成功,确定

    2024年02月01日
    浏览(57)
  • 合肥工业大学 宣城校区 数据结构与算法实验 队列、二叉树、查找和排序

    1.实验目标 熟练掌握队列的顺序存储结构和链式存储结构。 熟练掌握队列的有关算法设计,并在循环顺序队列和链队列上实现。 根据具体给定的需求,合理设计并实现相关结构和算法。 2.实验内容和要求 循环顺序队列的实验要求 循环顺序队列结构和运算定义,算法的实现以

    2024年02月11日
    浏览(49)
  • 一、课程设计目的与任务《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以

    一、课程设计目的与任务 《数据结构》课程设计是为训练学生的数据组织能力和提高程序设计能力而设置的增强实践能力的课程。目的:学习数据结构课程,旨在使学生学会分析研究数据对象的特性,学会数据的组织方法,以便选择合适的数据的逻辑结构和存储结构以及相应

    2024年02月21日
    浏览(71)
  • 数据结构之索引查找(分块查找)

    活动地址:CSDN21天学习挑战赛   作者简介:大家好我是小唐同学(๑؂๑),为梦想而奋斗的小唐,让我们一起加油!!! 个人主页: 小唐同学(๑؂๑)的博客主页 系列专栏:数据结构 博友们如果也是新手入门数据结构我希望大家可以多加练习 数据结构题库在牛客网就有已

    2024年02月02日
    浏览(53)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包