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

实验七 查找

    • 折半查找(二分法)
    • 哈希表的插入和查找

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


对于想要获取此实验报告和源代码的同学,欢迎光顾小生寒舍 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.
    数据结构与算法上机实验七 查找_第1张图片

哈希表的插入和查找

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

  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官网链接这个平台数据结构与算法上机实验七 查找_第2张图片,不止有较为详尽的算法介绍,图文都会比较直观,掌握数据结构和算法等知识足够!!
链接:https://www.geeksforgeeks.org/sorting-algorithms/.
数据结构与算法上机实验七 查找_第3张图片

附件: 源代码

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

折半查找(二分法)

#include 

// 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 //NULL等   
#include //exit()、 rand()   
#include //malloc   
#include //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 


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

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


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

你可能感兴趣的:(#,《数据结构与算法》上机实验)