数据结构与算法上机实验七 查找

GitHub 微信公众号 知乎 B站 CSDN

本次继续更新数据结构与算法这门课的上机实验,并且从本次开始将持续更新三篇关于排序和查找的内容——最根本的操作,主要涉及折半查找哈希表查找
特此感谢, 实验过程中邓老师的指导和帮助!


对于想要获取此实验报告和源代码的同学,欢迎光顾小生寒舍 GitHub:https://github.com/ChromeWei?tab=repositories

实验内容
一、编写函数实现折半查找。
二、实现一个最简单的哈希表的插入和查找。

备注:鉴于方便大家对折半查找的理解,我查找了很多相关CSDN平台上也没有写得较为细致的博文,所以我打算将我之前学习时用的平台推荐给大家GeeksforGeeks;对于哈希表的插入和查找我推荐一个博客的讲解,连接在下面。(小生先谢过作者,如涉及侵权,亲联系我即删 🙏)

折半查找(二分法)

  1. 折半查找https://blog.csdn.net/weixin_44321600/article/details/86671672.
  2. Binary Search https://www.geeksforgeeks.org/binary-search/.
  3. [C语言] 选择排序之直接选择排序的特性及实现https://www.cnblogs.com/usingnamespace-caoliu/p/9428115.html.
    GeeksforGeeks

哈希表的插入和查找

本算法中采用的构造哈希表的方法有:

  1. 构造哈希函数的方法:【除留余数法】
    H(key) = key MOD p (p ≤ m),其中m为表长,本算法中取p=m;(一般情况下,可选p为质数或不包含小于20的质因数的合数)
  2. 处理冲突的方法:【开放定址法】
    Hi = (H(key) + di) MOD m, i=1,2,3,…,k(k <= m - 1),其中di为增量序列,可有下列三种取法:
    (1) 线性探索再散列:di = 1,2,3,…,m-1
    (2) 二次探索再散列:di = 1,-12,2,-22,…,±k^2(k <= m - 1)
    (3) 伪随机探索再散列:di = 伪随机数序列

引用自:哈希表查找C实现(详细注释)http://blog.csdn.net/shengwusuoxi/article/details/8148460.



本篇重点: 但是最为推荐的是GeeksforGeeks官网链接这个平台GeeksforGeeks,不止有较为详尽的算法介绍,图文都会比较直观,掌握数据结构和算法等知识足够!!
链接:https://www.geeksforgeeks.org/sorting-algorithms/.
在这里插入图片描述

附件: 源代码

(测试环境:Win10, VisualC++ 6.0)

折半查找(二分法)

#include <stdio.h>

// A recursive binary search function. It returns location of x in
// given array arr[l..r] is present, otherwise -1
int binarySearch(int arr[], int l, int r, int x)
{
   if (r >= l)
   {
        int mid = l + (r - l)/2;

        // If the element is present at the middle itself
        if (arr[mid] == x)  return mid;

        // If element is smaller than mid, then it can only be present
        // in left subarray
        if (arr[mid] > x) return binarySearch(arr, l, mid-1, x);

        // Else the element can only be present in right subarray
        return binarySearch(arr, mid+1, r, x);
   }

   // We reach here when element is not present in array
   return -1;
}

int main(void)
{
   int arr[] = {2, 3, 4, 10, 40};
   int n = sizeof(arr)/ sizeof(arr[0]);
   
   //int x = 10;
   int x;
   printf("Please input a element will be found:");
   scanf("%d",&x);
   int result = binarySearch(arr, 0, n-1, x);
   (result == -1)? printf("%d is not present in array.", x)
                 : printf("%d is present at index %d.", x, result+1);
   return 0;
}

哈希表查找

#include <stdio.h>//NULL等   
#include <stdlib.h>//exit()、 rand()   
#include <malloc.h>//malloc   
#include <math.h>//OVERFLOW、pow() 

#define NULL_KEY 0//0为无记录标志 
#define N 15//数组可容纳的记录个数
  
static int m;//内部链接静态变量,m为哈希表表长 

typedef int KeyType;//关键字类型   
typedef struct ElemType  
{//数据元素(记录)类型   
    KeyType key;  
    int order;  
}ElemType;  
  
//对两个数值型关键字的比较约定为如下的宏定义。   
#define EQ(a,b) ((a) == (b))   
#define LT(a,b) ((a) < (b))   
#define LE(a,b) ((a) <= (b))

void Visit(int p,ElemType r)  
{  
    printf("address = %d(%d,%d)\n",p,r.key,r.order);  
}  

static int hashsize[] = {11,19,29,37};//内部链接静态变量,哈希表容量(表长m)递增表,一个合适的素数序列。   
typedef struct HashTable  
{//哈希表的存储结构   
    ElemType *elem;//记录存储基址变量,动态分配数组   
    int count;//当前记录个数   
    int sizeindex;//hashsize[sizeindex]为当前表长   
}HashTable;  
  
//宏定义   
typedef int Status; // Status是函数的类型,其值是函数结果状态代码,如下边三个宏定义   
#define SUCCESS 1 //查找成功   
#define UNSUCCESS 0//查找失败   
#define DUPLICATE -1//记录重复   
  
void InitHashTable(HashTable &H)  
{//初始化哈希表,构造一个记录为空的哈希表   
    int i;  
    H.sizeindex = 0;//初始化表长数组索引为0   
    m = hashsize[H.sizeindex];//初始化表长为hashsize[0]   
    H.count = 0;//初始化记录数为0   
    H.elem = (ElemType *)malloc(m * sizeof(ElemType));//动态分配记录数组   
    if (!H.elem)  
    {//分配失败   
        exit(OVERFLOW);  
    }  
    for (i = 0; i < m; ++i)  
    {//初始化记录数组关键字为空   
        H.elem[i].key = NULL_KEY;//未填记录的标志   
    }  
} 
 
void DestroyHashTable(HashTable &H)  
{//销毁哈希表   
    free(H.elem);//释放动态记录数组   
    H.elem = NULL;//指针置为空   
    H.count = 0;//记录数置为为0   
    H.sizeindex = 0;//表长索引项置为0   
}  
  
unsigned Hash(KeyType k)  
{//返回哈希函数求得的哈希地址(用除留余数法构造的一个简单的哈希函数)   
    return k % m;// H(key) = key MOD p (p ≤ m),取p=m   
}  

void collision(KeyType &k,int &p,int i)  
{//用开放定址法处理冲突,其中p为处理后所得的哈希地址,i为冲突次数。   
    p = (Hash(k) + i) % m;  
}

Status SearchHash(HashTable H,KeyType k,int &p,int &c)  
{//在开放地址哈希表中查找关键字为K的记录,若查找成功,以p指示记录在表中的位置,并返回SUCCESS;   
 //否则以p指示插入位置,并返回UNSUCCESS。c以计冲突次数,其初值为0,供建表插入时参考   
    p = Hash(k);//用哈希函数计算哈希地址   
    while (H.elem[p].key != NULL_KEY && !EQ(H.elem[p].key,k))  
    {//该位置中填有记录,并且与待查记录不相等   
        c++;  
        if (c < m)  
        {//处理冲突次数未超出m - 1,则继续处理冲突   
            collision(k,p,c);  
        }  
        else  
        {//超出最大处理次数,H中位找到记录   
            break;  
        }  
    }  
    if (EQ(H.elem[p].key,k))  
    {//查找成功   
        return SUCCESS;  
    }  
    else  
    {//查找失败   
        return UNSUCCESS;  
    }  
} 
 
void RecreateHashTable(HashTable &);//对函数RecreateHashTable()的声明   
  
Status InsertHash(HashTable &H,ElemType e)  
{  
    int p,c = 0;//冲突次数初始为0   
    if (SearchHash(H,e.key,p,c))  
    {//查找成功   
        return DUPLICATE;//H中已有与e有相同关键字的记录,不插入   
    }  
    else if (c < hashsize[H.sizeindex]/2)  
    {//未找到,冲突次数c也未达到上限(c的阀值可调,但最大不超过hashsize[H.sizeindex] - 1)   
        H.elem[p] = e;//在H中插入数据元素e   
        ++H.count;  
        return SUCCESS;//插入成功   
    }  
    else  
    {//未找到,但冲突次数c已达到上限   
        RecreateHashTable(H);//重建哈希表   
        return UNSUCCESS;//插入不成功   
    }  
}  
  
void RecreateHashTable(HashTable &H)  
{  
    int i,count = H.count;//H中原有记录个数   
    ElemType *p,*elem = (ElemType *)malloc(count *sizeof(ElemType));//动态生成存放哈希表H原有数据的空间   
    p =elem;  
    for (i = 0; i < m; ++i)  
    {//将原有的所有记录,保存到elem中   
        if (!EQ(H.elem[i].key,NULL_KEY))  
        {//H在该单元有记录   
            *p++ = H.elem[i];//将记录依次存入elem   
        }  
    }  
    H.count = 0;//将原有记录数置为0,为下面调用InserHash做准备   
    H.sizeindex++;//表长数组索引加1   
    m = hashsize[H.sizeindex];//新的存储容量(表长)   
    H.elem = (ElemType *)realloc(H.elem,m*sizeof(ElemType));//以新的存储容量重新生成空哈希表H   
    for (i = 0; i < m; ++i)  
    {//初始化新的哈希表   
        H.elem[i].key = NULL_KEY;//未填记录   
    }  
    for (p = elem; p < elem + count; ++p)  
    {//将原表中的记录重新存储到新的哈希表中   
        InsertHash(H,*p);  
    }  
    free(elem);//释放elem的存储空间   
}  

void TraverseHash(HashTable H,void (*Visit)(int,ElemType))  
{//按哈希地址的顺序遍历哈希表H   
    int i;  
    printf("哈希地址 0 ~ %d\n",m - 1);  
    for (i = 0; i < m; ++i)  
    {//对于整个哈希表H   
        if (!EQ(H.elem[i].key,NULL_KEY))  
        {//H在第i个单元有记录   
            Visit(i,H.elem[i]);//访问第i个数据   
        }  
    }  
} 
   
int main(void)  
{  
    ElemType r[N];//记录数组   
    HashTable h;  
    int i,n = 0,p = 0;  
    Status s;  
    KeyType k;  
    FILE *f;//文件指针类型   
    f = fopen("Records.txt","r");//打开记录文件Record.txt   
    do  
    {  
        i = fscanf(f,"%d%d",&r[p].key,&r[p].order);//先将记录暂存入记录数组r[p]   
        if (i != -1)  
        {//输入数据成功   
            p++;  
        }  
    } while (!feof(f) && p < N);//未到达数据文件结尾且记录数组未满   
    fclose(f);//关闭数据文件   
    InitHashTable(h);  
    for (i = 0; i < p - 1; ++i)  
    {//在h中插入前p-1个记录(最后一个记录不插入,插入最后一个记录会重建哈希表)   
        s = InsertHash(h,r[i]);  
        if (DUPLICATE == s)  
        {  
            printf("表中已有关键字为%d的记录,无法再插入记录(%d,%d)\n",r[i].key,r[i].key,r[i].order);  
        }  
    }  
    printf("按哈希地址的顺序遍历哈希表:\n");  
    TraverseHash(h,Visit);  
    printf("请输入待查找记录的关键字:");  
    scanf("%d",&k);  
    s = SearchHash(h,k,p,n);  
    if (SUCCESS == s)  
    {//查找成功   
        Visit(p,h.elem[p]);//输出该记录   
    }  
    else  
    {//查找失败   
        printf("未找到\n");  
    }  
    s = InsertHash(h,r[i]);//插入最后一个记录(需重建哈希表)   
    if (UNSUCCESS == s)  
    {//插入不成功   
        s = InsertHash(h,r[i]);//重建哈希表后重新插入   
    }  
    printf("按哈希表地址的顺序遍历重建后的哈希表:\n");  
    TraverseHash(h,Visit);  
  
    printf("请输入待查找记录的关键字:");  
    scanf("%d",&k);  
    s = SearchHash(h,k,p,n);  
    if (SUCCESS == s)  
    {//查找成功   
        Visit(p,h.elem[p]);//输出该记录   
    }  
    else  
    {//查找失败   
        printf("未找到\n");  
    }  
    DestroyHashTable(h);  
    return 0;  
} 
Records.txt
	12 23 43 23 32 5 31 56 78 34 8 45 63 55 30 


上一篇:数据结构与算法上机实验六 排序(二)

下一篇:数据结构与算法上机实验专栏


欢迎各位订阅我,谢谢大家的点赞和专注!我会继续给大家分享我大学期间详细的实践项目。

在这里插入图片描述
在这里插入图片描述

微信扫一扫, 关注我


知识星球

专为求职面试中算法与数据结构的小伙伴,创了学习交流/刷题群(知识星球)!想要最快的提升算法与数据结构技能,和更多小伙伴一起来吧!

进群获取互联网大厂高频coding题库,告别刷题400道,分类整理的题库,算法思路和源代码实现配套,各个类型总结出来的解题模板,远比你一个人要强!

Click to see the more details

MaiweiAI-com | WeChat ID: Yida_Zhang2

机器学习+计算机视觉

数据结构查找实验代码 (1) 对下列数据表,分别采用二分查找算法实现查找,给出查找过程依次所比较的元素(的下标),并以二分查找的判定树来解释。 第一组测试数据: 数据表为 (1,2,3,4,6,7,8,9,10,11,12,13,17,18,19,20,24,25,26,30,35,40,45,50,,100) 查找的元素分别为: 2,8,20, 30,50,5,15,33,110 第二组数据: 数据表为 (2,3,5,7,8,10,12,15,18,20,22,25,30,35,40,45,50,55,60, 80,100) 查找的元素分别为: 22,8,80,3,100,1,13,120 (2) 设计出在二叉排序树中插入结点的算法,在此基础上实现构建二叉排序树的算法。 测试数据:构建二叉排序树的输入序列如下: 第一组数据: 100,150,120,50,70,60,80,170,180,160,110,30,40,35,175 第二组数据: 100,70,60,80,150,120,50,160,30,40,170,180,175,35 (3) 设计算法在二叉排序树中查找指定值的结点。 测试数据:在任务中第一组测试数据所构造的二叉排序树中,分别查找下列元素: 150,70,160,190,10,55,175 (4) 设计算法在二叉排序树中删除特定值的结点。 测试数据:在任务(1)中第一组测试数据所构造的二叉排序树中,分别删除下列元素:30,150,100 (5) 已知整型数组A[1..26]递增有序,设计算法以构造一棵平衡的二叉排序树来存放该数组中的所有元素。 测试数据:数组元素分别为: 第一组数据: (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26) 第二组数据: (1,3,6,10,15,21,28,36,45,55,66,78,91,105,120,136,153,171,190,210,231,253,277,302,328)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Charmve

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

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

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

打赏作者

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

抵扣说明:

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

余额充值