educoder头歌数据结构 查找 第2关:实现散列查找(答案无错AC版)

                                                          本文已收录于专栏

                 🌲《educoder数据结构与算法_大耳朵宋宋的博客-CSDN博客》🌲

任务描述

本关要求通过补全函数ILH_InsKeyILH_DelKey来分别实现插入和删除操作。

相关知识

本关讨论散列存储,散列函数使用除留余数法,冲突解决方法采用独立链表地址法。假设有 8 个关键码: 7 , 15 , 23 , 31 , 12 , 14 , 10 , 17 ,采用散列函数hash(key)=key%7,其存储结构图如图 1 所示,它由 7 个独立链表组成,散列值相同的关键码在同一个链表里,独立链表的头结点组成散列表,一共 7 行,编号 0 , 1 , … , 6 。独立链表的每个结点是一个 struct HNode 结构,其定义如下:

 
  1. struct HNode {
  2. int key; //假设关键码为整数
  3. HNode* next;
  4. };

在散列表中,如果表项的key字段等于 0 (假设有效的关键码值不等于 0 ),则表示该行是一条空链表,例如图 1 中编号为 4 和编号为 6 的行。

散列表的开始地址保存在pn中,散列表的行数为n(图 1 中,n=7),将pnn组织成结构:

 
  1. struct LHTable {
  2. HNode* pn; //指向散列表,每个表结点是独立链表的表头结点
  3. int n; //散列表的长度,一般取(小于等于数据个数的最大)质数
  4. };

定义如下操作,各操作函数的功能详见下面给出的代码文件 indLnkHash.cpp 的代码框架:

 
  1. LHTable* ILH_Create(int n);
  2. void ILH_Free(LHTable* pt);
  3. bool ILH_InsKey(LHTable* pt, int x);
  4. bool ILH_FindKey(LHTable* pt, int x);
  5. bool ILH_DelKey(LHTable* pt, int x);
  6. void ILH_Print(LHTable *pt);

编程要求

本关的编程任务是补全 step2/indLnkHash.cpp 文件中的ILH_InsKeyILH_DelKey函数来分别实现插入和删除操作。

  • 具体请参见后续测试样例。

本关涉及的代码文件 indLnkHash.cpp 的代码框架如下:

 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <time.h>
  4. #include "indLnkHash.h"
  5. LHTable* ILH_Create(int n)
  6. //创建散列表, n为表长度,最佳取值:n取小于等于数据个数的最大质数
  7. {
  8. HNode* pn=(HNode*)malloc(sizeof(HNode)*n);
  9. for (int i=0; i<n; i++) {
  10. pn[i].key=0;
  11. pn[i].next=NULL;
  12. }
  13. LHTable* pt=(LHTable*)malloc(sizeof(LHTable));
  14. pt-> pn=pn;
  15. pt->n=n;
  16. return pt;
  17. }
  18. void ILH_Free(LHTable* pt)
  19. //释放散列表
  20. {
  21. if (pt==NULL) return;
  22. for (int i=0; i<pt->n; i++) {
  23. HNode* curr=pt->pn[i].next;
  24. while (curr) {
  25. HNode* next=curr->next;
  26. free(curr);
  27. curr=next;
  28. }
  29. }
  30. free(pt->pn);
  31. free(pt);
  32. }
  33. bool ILH_InsKey(LHTable* pt, int x)
  34. //插入关键码x
  35. //返回true,表示插入成功
  36. //返回false,表示插入失败(关键码已经存在)
  37. {
  38. // 请在此添加代码,补全函数ILH_InsKey
  39. /********** Begin *********/
  40. /********** End **********/
  41. }
  42. bool ILH_FindKey(LHTable* pt, int x)
  43. //查找关键码x
  44. //返回true表示找到
  45. //返回false表示没找到
  46. {
  47. int d=x%pt->n;
  48. if (pt->pn[d].key==0) {
  49. return false;
  50. }
  51. else if (pt->pn[d].key==x)
  52. return true;
  53. HNode* curr=pt->pn[d].next;
  54. while (curr && curr->key!=x) curr=curr->next;
  55. if (curr) return true;
  56. else return false;
  57. }
  58. bool ILH_DelKey(LHTable* pt, int x)
  59. //删除关键码
  60. //返回true表示该关键码存在,且成功删除
  61. //返回false表示该关键码不存在
  62. {
  63. // 请在此添加代码,补全函数ILH_DelKey
  64. /********** Begin *********/
  65. /********** End **********/
  66. }
  67. void ILH_Print(LHTable *pt)
  68. {
  69. for (int i=0; i<pt->n; i++) {
  70. printf("%5d: ", i);
  71. if (pt->pn[i].key) {
  72. printf("%d ", pt->pn[i].key);
  73. HNode* curr=pt->pn[i].next;
  74. while (curr) {
  75. printf("-> %d ", curr->key);
  76. curr=curr->next;
  77. }
  78. printf("\n");
  79. }
  80. else
  81. printf("-\n");
  82. }
  83. }

测试说明

本关的测试文件是 step2/Main.cpp ,测试过程如下:

  1. 平台编译 step2/Main.cpp ,然后链接相关程序库并生成 exe 可执行文件;

  2. 平台运行该 exe 可执行文件,并以标准输入方式提供测试输入;

  3. 平台获取该 exe 可执行文件的输出,然后将其与预期输出对比,如果一致则测试通过;否则测试失败。

输入输出格式说明

输入格式: 首先输入一个正整数n,创建一个长n的散列表。 然后输入多个操作:如果输入 “insert” ,则后面跟一个数x,表示将x插入;如果输入 “delete” ,则后面跟一个数x,表示将x删除;如果输入 “end” ,表示输入结束。

输出格式: 输出n个独立链表。

以下是平台对 step2/Main.cpp 的样例测试集:

样例输入: 11 insert 54 insert 77 insert 94 insert 89 insert 14 insert 45 insert 76 insert 23 insert 43 insert 47 end

样例输出: 0: 77 1: 89 -> 45 -> 23 2: - 3: 14 -> 47 4: - 5: - 6: 94 7: - 8: - 9: - 10: 54 -> 76 -> 43

开始你的任务吧,祝你成功

AC_Code

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "indLnkHash.h"
LHTable* ILH_Create(int n)
//创建散列表, n为表长度,最佳取值:n取小于等于数据个数的最大质数
{
    HNode* pn=(HNode*)malloc(sizeof(HNode)*n);
    for (int i=0; i<n; i++) {
        pn[i].key=0;
        pn[i].next=NULL;
    }
    LHTable* pt=(LHTable*)malloc(sizeof(LHTable));
    pt-> pn=pn;
    pt->n=n;
    return pt;
}
void ILH_Free(LHTable* pt)
//释放散列表
{
    if (pt==NULL) return;
    for (int i=0; i<pt->n; i++) {
        HNode* curr=pt->pn[i].next;
        while (curr) {
            HNode* next=curr->next;
            free(curr);
            curr=next;
        }
    }
    free(pt->pn);
    free(pt);
}
bool ILH_InsKey(LHTable* pt, int x)
//插入关键码x
//返回true,表示插入成功
//返回false,表示插入失败(关键码已经存在)
{
    /*请在BEGIN和END之间实现你的代码*/
    /*****BEGIN*****/
    int d=x%pt->n;
    if (pt->pn[d].key==0) {
        pt->pn[d].key=x;
        return true;
    }
    else if (pt->pn[d].key==x) 
        return false;
    HNode* prev=&(pt->pn[d]);
    HNode* curr=pt->pn[d].next;
    while (curr && curr->key!=x) {prev=curr; curr=curr->next;}
    if (curr) return  false;
    HNode* pnode=(HNode*)malloc(sizeof(HNode));
    pnode->key=x;
    pnode->next=NULL;//pt->pn[d].next;
    prev->next=pnode;
    return true;
    /******END******/
    /*请不要修改[BEGIN,END]区域外的代码*/
}
bool ILH_FindKey(LHTable* pt, int x)
//查找关键码x
//返回true表示找到
//返回false表示没找到
{
    int d=x%pt->n;
    if (pt->pn[d].key==0) {
        return false;
    }
    else if (pt->pn[d].key==x) 
        return true;
    HNode* curr=pt->pn[d].next;
    while (curr && curr->key!=x) curr=curr->next;
    if (curr) return  true;
    else return false;
}
bool ILH_DelKey(LHTable* pt, int x)
//删除关键码
//返回true表示该关键码存在,且成功删除
//返回false表示该关键码不存在
{
    /*请在BEGIN和END之间实现你的代码*/
    /*****BEGIN*****/
    int d=x%pt->n;//关键码x的散列值d
    if (pt->pn[d].key==0) {
        return false;
    }
    else if (pt->pn[d].key==x)  {
        if (pt->pn[d].next ==NULL) 
            pt->pn[d].key=0;
        else {
            HNode* first=pt->pn[d].next;
            pt->pn[d].key=first->key;
            pt->pn[d].next=first->next;
            free(first);
        }
        return true;
    }
    HNode* prev=&(pt->pn[d]);
    HNode* curr=pt->pn[d].next;
    while (curr && curr->key!=x) {prev=curr; curr=curr->next;}
    if (curr==NULL) return false;
    prev->next=curr->next;
    free(curr);
    return true;
    /******END******/
    /*请不要修改[BEGIN,END]区域外的代码*/
}
void ILH_Print(LHTable *pt)
{
    for (int i=0; i<pt->n; i++) {
        printf("%5d:", i);
        if (pt->pn[i].key) {
            printf("%d", pt->pn[i].key);
            HNode* curr=pt->pn[i].next;
            while (curr) {
                printf("->%d", curr->key);
                curr=curr->next;
            }
            printf("\n");
        }
        else 
            printf("-\n");
    }
}

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1. 实现线性表的二分(折半)查找算法 线性表的二分查找算法要求线性表中的元素必须是有序的。具体实现步骤如下: 1. 首先确定待查找的区间的左右边界,即 low 和 high,其中 low 初始值为 0,high 初始值为 n-1,n 为数组的长度。 2. 计算中间位置 mid,即 mid = (low + high) / 2。 3. 比较要查找的值 key 和 mid 位置上的值 arr[mid] 的大小。如果 key 等于 arr[mid],则查找成功,返回 mid;否则,如果 key 小于 arr[mid],则在左半边继续查找;如果 key 大于 arr[mid],则在右半边继续查找。 4. 重复执行第二步和第三步,直到找到 key,或者 low 大于 high,此时查找失败,返回 -1。 以下是线性表的二分查找算法的 Python 代码: ```python def binary_search(arr, key): n = len(arr) low, high = 0, n-1 while low <= high: mid = (low + high) // 2 if arr[mid] == key: return mid elif arr[mid] < key: low = mid + 1 else: high = mid - 1 return -1 ``` 2. 实现树表的二叉排序树的创建、插入、删除、查找算法 二叉排序树(Binary Search Tree,简称 BST)是一种基于二叉树的数据结构,它的每个节点都包含一个键字和两个子树,其中左子树上所有节点的键字都小于它的父节点的键字,右子树上所有节点的键字都大于它的父节点的键字。 二叉排序树的创建、插入、删除和查找算法的具体实现如下: 创建二叉排序树: ```python class TreeNode: def __init__(self, val): self.val = val self.left = None self.right = None def create_bst(arr): if not arr: return None root = TreeNode(arr[0]) for i in range(1, len(arr)): insert_bst(root, arr[i]) return root ``` 插入节点: ```python def insert_bst(root, val): if not root: root = TreeNode(val) return if val < root.val: if not root.left: root.left = TreeNode(val) else: insert_bst(root.left, val) elif val > root.val: if not root.right: root.right = TreeNode(val) else: insert_bst(root.right, val) ``` 删除节点: ```python def delete_bst(root, val): if not root: return root if val < root.val: root.left = delete_bst(root.left, val) elif val > root.val: root.right = delete_bst(root.right, val) else: # 如果要删除的节点只有一个子节点或者没有子节点 if not root.left: temp = root.right root = None return temp elif not root.right: temp = root.left root = None return temp # 如果要删除的节点有两个子节点 temp = min_value_node(root.right) root.val = temp.val root.right = delete_bst(root.right, temp.val) return root def min_value_node(node): while node.left: node = node.left return node ``` 查找节点: ```python def search_bst(root, val): if not root: return None if root.val == val: return root elif root.val > val: return search_bst(root.left, val) else: return search_bst(root.right, val) ``` 3. 实现表的查找方法 表(Hash Table)是一种基于数组的数据结构,它利用函数(Hash Function)将键字映射到数组中的一个位置,以实现快速的查找、插入和删除操作。 查找方法的具体实现步骤如下: 1. 根据给定的键字 key,计算出它在数组中的位置,即 hash(key)。 2. 如果该位置上没有元素,则查找失败,返回 -1。 3. 如果该位置上的元素的键字等于 key,则查找成功,返回该元素的下标。 4. 如果该位置上的元素的键字不等于 key,则继续查找下一个位置,直到找到 key,或者遇到空位置,此时查找失败,返回 -1。 以下是表的查找方法的 Python 代码: ```python def hash_func(key): return key % 10 def hash_search(arr, key): n = len(arr) pos = hash_func(key) while arr[pos] and arr[pos] != key: pos = (pos + 1) % n if not arr[pos]: return -1 else: return pos ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

幸福西西弗斯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值