• 哈希表— —链式实现


    哈希表的故事导入

    故事情节

            为了提高开发团队精神,缓解工作压力,某 IT 公司组织开发团队的 12 位男同事和测试团队 的 12 位女同事开展真人 CS 4vs4 野战联谊!面对性感的女同事,男同事们个个摩拳擦掌,跃跃欲 试!

            野战活动那天,根据男女搭配,干活不累的原则,带队的专业教练让男同事站成一排,女同 事站成一排,然后要求从女生这排开始从 1 开始报数,每个报数的队员都要记住自己的编号: 1, 2, 3,4。。。。。。林子里响起了百灵鸟般的报数声!

    报数时,教练发给每人一个白色的臂章贴在肩膀上,每个臂章上写着报数人自己报过的编号!

    当所有人都报完数后,教练发出命令将 24 人均分成 6 个组!

    编号除 6 能整除的为第一组: 6 12 18 24

    编号除 6 余数为 1 的为第二组: 1 7 13 19

    编号除 6 余数为 2 的为第三组: 2 8 14 20

    编号除 6 余数为 3 的为第四组: 3 9 15 21

    编号除 6 余数为 4 的为第五组: 4 10 16 22

    编号除 6 余数为 5 的为第六组: 5 11 17 23

    通过这种编号方式划分队列,无论队员归队,还是裁判确89认79队43员8身40份1,11都1非常方便,此后林 子里传来隆隆的笑声和枪炮声! 这种编号的方式就是高效的散列,我们俗称“哈希”! 以上过程是通过把关键码值 key(编号)映射到表中一个位置(数组的下标)来访问记录,以加 快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

    哈希表的原理精讲

    哈希表 - 散列表,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法

    键(key): 组员的编号 如, 1 、 5 、 19 。 。 。

    值(value): 组员的其它信息(包含 性别、年龄和战斗力等)

    索引: 数组的下标(0,1,2,3,4) ,用以快速定位和检索数据

    哈希桶: 保存索引的数组(链表或数组),数组成员为每一个索引值相同的多个元素

    哈希函数: 将组员编号映射到索引上,采用求余法 ,如: 组员编号 19

     

    哈希链表的算法实现

    哈希链表数据结构的定义

    1. #define DEFAULT_SIZE 16
    2. typedef struct _ListNode
    3. {
    4. struct _ListNode *next;
    5. int key;
    6. void *data;
    7. }ListNode;
    8. typedef ListNode *List;
    9. typedef ListNode *Element;
    10. typedef struct _HashTable
    11. {
    12. int TableSize;
    13. List *Thelists;
    14. }HashTable;

    哈希函数

    1. /*根据 key 计算索引,定位 Hash 桶的位置*/
    2. int Hash(int key, int TableSize)
    3. {
    4. return (key%TableSize);
    5. }

    哈希链表初始化

    1. /*初始化哈希表*/
    2. HashTable *InitHash(int TableSize)
    3. {
    4. int i = 0;
    5. HashTable *hTable = NULL;
    6. if (TableSize <= 0) {
    7. TableSize = DEFAULT_SIZE;
    8. }
    9. hTable = (HashTable *)malloc(sizeof(HashTable));
    10. if (NULL == hTable)
    11. {
    12. printf("HashTable malloc error.\n");
    13. return NULL;
    14. }
    15. hTable->TableSize = TableSize;
    16. //为 Hash 桶分配内存空间,其为一个指针数组
    17. hTable->Thelists = (List *)malloc(sizeof(List)*TableSize);
    18. if (NULL == hTable->Thelists)
    19. {
    20. printf("HashTable malloc error\n");
    21. free(hTable);
    22. return NULL;
    23. }
    24. //为 Hash 桶对应的指针数组初始化链表节点
    25. for (i = 0; i < TableSize; i++)
    26. {
    27. hTable->Thelists[i] = (ListNode *)malloc(sizeof(ListNode));
    28. if (NULL == hTable->Thelists[i])
    29. {
    30. printf("HashTable malloc error\n");
    31. free(hTable->Thelists);
    32. free(hTable);
    33. return NULL;
    34. }
    35. else
    36. {
    37. memset(hTable->Thelists[i], 0, sizeof(ListNode));
    38. }
    39. }
    40. return hTable;
    41. }

    哈希链表插入元素

    1. /*哈希表插入元素,元素为键值对*/
    2. void Insert(HashTable *HashTable, int key, void *value )
    3. {
    4. Element e=NULL, tmp=NULL;
    5. List L=NULL;
    6. e = Find(HashTable, key);
    7. if (NULL == e)
    8. {
    9. tmp = (Element)malloc(sizeof(ListNode));
    10. if (NULL == tmp)
    11. {
    12. printf("malloc error\n");
    13. return;
    14. }
    15. L = HashTable->Thelists[Hash(key, HashTable->TableSize)];
    16. tmp->data = value;
    17. tmp->key = key;
    18. tmp->next = L->next;
    19. L->next = tmp;
    20. }
    21. else
    22. printf("the key already exist\n");
    23. }

    哈希链表查找元素

    1. /*从哈希表中根据键值查找元素*/
    2. Element Find(HashTable *HashTable, int key)
    3. {
    4. int i = 0;
    5. List L = NULL;
    6. Element e = NULL;
    7. i = Hash(key, HashTable->TableSize);
    8. L = HashTable->Thelists[i];
    9. e = L->next;
    10. while (e != NULL && e->key != key)
    11. e = e->next;
    12. return e;
    13. }

    哈希链表删除元素

    1. /*哈希表删除元素,元素为键值对*/
    2. void Delete(HashTable *HashTable, int key )
    3. {
    4. Element e=NULL, last=NULL;
    5. List L=NULL;
    6. int i = Hash(key, HashTable->TableSize);
    7. L = HashTable->Thelists[i];
    8. last = L;
    9. e = L->next;
    10. while (e != NULL && e->key != key)
    11. {
    12. last = e;
    13. e = e->next;
    14. }
    15. if(e)
    16. { //如果键值对存在
    17. last->next = e->next;
    18. delete(e);
    19. }
    20. }

    源码实现:

    hash_table.h

    1. #pragma
    2. #define DEFAULT_SIZE 16
    3. typedef struct _ListNode
    4. {
    5. int key;
    6. void* data;
    7. struct _ListNode* next;
    8. }ListNode;
    9. typedef ListNode* List;
    10. typedef ListNode* Element;
    11. typedef struct _HashTable
    12. {
    13. int TableSize;
    14. List* Thelists;
    15. }HashTable;

    hash_table.cpp

    1. #include
    2. #include
    3. #include
    4. #include "hash_table.h"
    5. int Hash(int key, int TableSize)
    6. {
    7. return (key % TableSize);
    8. }
    9. //初始化哈希表
    10. HashTable* InitHash(int TableSize)
    11. {
    12. HashTable* hTable = NULL;
    13. int i = 0;
    14. hTable = (HashTable*)malloc(sizeof(HashTable));
    15. if (hTable == NULL)
    16. {
    17. printf("分配哈希表失败!");
    18. return NULL;
    19. }
    20. if (TableSize < 0)
    21. {
    22. TableSize = DEFAULT_SIZE;
    23. }
    24. hTable->TableSize = TableSize;
    25. hTable->Thelists = (List *)malloc(sizeof(List) * TableSize);
    26. if (hTable->Thelists == NULL)
    27. {
    28. printf("分配失败!");
    29. free(hTable);
    30. return NULL;
    31. }
    32. for (int i = 0; i < TableSize; i++)
    33. {
    34. //if(sizeof(ListNode)
    35. hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
    36. if (hTable->Thelists[i] == NULL)
    37. {
    38. printf("分配失败!");
    39. free(hTable->Thelists);
    40. free(hTable);
    41. return NULL;
    42. }
    43. else
    44. {
    45. memset(hTable->Thelists[i], 0, sizeof(ListNode));
    46. }
    47. }
    48. return hTable;
    49. }
    50. //从哈希表中根据键值查找元素
    51. Element Find(HashTable* HashTable, int key)
    52. {
    53. int i = Hash(key, HashTable->TableSize);
    54. List L = NULL;
    55. L= HashTable->Thelists[i];
    56. Element e = NULL;
    57. e = L->next;
    58. while (e != NULL && e->key != key)
    59. {
    60. e = e->next;
    61. }
    62. return e;
    63. }
    64. void Insert(HashTable* HashTable, int key, void* value)
    65. {
    66. int i = 0;
    67. i = Hash(key, HashTable->TableSize);
    68. List L = NULL;
    69. L = HashTable->Thelists[i];
    70. Element tmp = Find(HashTable, key);
    71. if (!tmp)
    72. {
    73. Element e = NULL;
    74. e = (Element)malloc(sizeof(ListNode));
    75. if (!e)
    76. {
    77. printf("分配失败!");
    78. return;
    79. }
    80. e->data = value;
    81. e->key = key;
    82. e->next = L->next;
    83. L->next = e;
    84. }
    85. else
    86. {
    87. printf("表中有重复键值");
    88. }
    89. }
    90. void Delete(HashTable* HashTable, int key)
    91. {
    92. int i = Hash(key, HashTable->TableSize);
    93. List L = NULL;
    94. L = HashTable->Thelists[i];
    95. Element next = NULL, cur = NULL;
    96. next = L->next;
    97. cur = L;
    98. while (next != NULL && next->key != key)
    99. {
    100. cur = next;
    101. next = next->next;
    102. }
    103. if (next)
    104. {
    105. cur->next = next->next;
    106. delete(next);
    107. }
    108. }
    109. void* Retrieve(Element e)
    110. {
    111. return e ? e->data : NULL;
    112. }
    113. void Destory(HashTable* HashTable)
    114. {
    115. int i = 0;
    116. List L = NULL;
    117. Element cur = NULL, next = NULL;
    118. for (int i = 0; i < HashTable->TableSize; i++)
    119. {
    120. L = HashTable->Thelists[i];
    121. cur = L->next;
    122. while (cur != NULL)
    123. {
    124. next = cur->next;
    125. free(cur);
    126. cur = next;
    127. }
    128. free(L);
    129. }
    130. free(HashTable->Thelists);
    131. free(HashTable);
    132. }
    133. int main(void)
    134. {
    135. char *elems[] = { "翠花","小芳","老师" };
    136. int i = 0;
    137. HashTable* HashTable;
    138. HashTable = InitHash(31);
    139. Insert(HashTable, 1, elems[0]);
    140. Insert(HashTable, 2, elems[1]);
    141. Insert(HashTable, 3, elems[2]);
    142. Delete(HashTable, 1);
    143. for (i = 0; i < 4; i++)
    144. {
    145. Element e = Find(HashTable, i);
    146. if (e)
    147. {
    148. printf("%s\n", (const char*)Retrieve(e));
    149. }
    150. else
    151. {
    152. printf("Not found [key:%d]\n", i);
    153. }
    154. }
    155. system("pause");
    156. return 0;
    157. }
  • 相关阅读:
    【基于能量的模型】
    安卓大作业 图书管理APP
    浅谈HTTP
    [数据分析与可视化] 基于Python绘制简单动图
    ESP8266开发环境搭建踩坑
    【Nano Framework ESP32篇】使用 LCD 屏幕
    Swift 5.9 有哪些新特性(二)
    IS-IS
    浏览器网络无法连接github的解决办法
    SQL的ROUND函数用法及其实例
  • 原文地址:https://blog.csdn.net/m0_65635427/article/details/127811134