哈希表的故事导入
故事情节
为了提高开发团队精神,缓解工作压力,某 IT 公司组织开发团队的 12 位男同事和测试团队 的 12 位女同事开展真人 CS 4vs4 野战联谊!面对性感的女同事,男同事们个个摩拳擦掌,跃跃欲 试!
野战活动那天,根据男女搭配,干活不累的原则,带队的专业教练让男同事站成一排,女同 事站成一排,然后要求从女生这排开始从 1 开始报数,每个报数的队员都要记住自己的编号: 1, 2, 3,4。。。。。。林子里响起了百灵鸟般的报数声!
报数时,教练发给每人一个白色的臂章贴在肩膀上,每个臂章上写着报数人自己报过的编号!
通过这种编号方式划分队列,无论队员归队,还是裁判确89认79队43员8身40份1,11都1非常方便,此后林 子里传来隆隆的笑声和枪炮声!
这种编号的方式就是高效的散列,我们俗称“哈希”!
以上过程是通过把关键码值 key(编号)映射到表中一个位置(数组的下标)来访问记录,以加 快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表的原理
哈希表 - 散列表, 它是基于快速存储的角度设计的, 也是一种典型 “空间换时间” 的做法
键(key): 组员的编号 如, 1, 5, 19 …
值(value): 组员的其他信息(包括 性别, 年龄和战斗力等)
索引: 数组的下表(0,1,2,3,4), 用以快速定位和检索数据
哈希桶: 保存索引的数组(链表或数组), 数组成员为每一个索引值相同的多个元素
哈希函数: 将组员编号映射到索引上, 采用求余法, 如: 组员编号 19
哈希链表的算法实现
参考:
#include <iostream>
using namespace std;
#define DEFAULT_SIZE 16
typedef struct _ListNode
{
struct _ListNode* next;
int key;
void* data;
}ListNode;
typedef ListNode* List;
typedef ListNode* element;
typedef struct _HashTable
{
int TableSize; /* 哈希桶的数量 */
List* Thelists; /* 指针数组 */
}HashTable;
int Hash(void* key, int TableSize); /* 哈希函数 */
HashTable* InitHash(int TableSize); /* 初始化哈希表 */
void Insert(HashTable* HashTable, int key, void* valuue); /* 哈希表插入 */
void Delete(HashTable* HashTable, int key); /* 哈希表删除元素, 元素为键值对 */
element Find(HashTable* HashTable, int key);/* 哈希表的查找 */
void* Retrieve(element e); /* 哈希表元素中提取数据 */
void Destory(HashTable* HashTable);/* 哈希表的销毁 */
int Hash(int key, int TableSize)
{
return (key % TableSize);
}
HashTable* InitHash(int TableSize)
{
int i = 0;
HashTable* hTable = NULL;
if (TableSize <= 0)
{
TableSize = DEFAULT_SIZE;
}
hTable = (HashTable*)malloc(sizeof(HashTable));
if (hTable == NULL)
{
printf("HashTable malloc error.\n");
return NULL;
}
hTable->TableSize = TableSize;
/* 为Hash桶分配内存空间, 其为一个指针数组 */
hTable->Thelists = (List*)malloc(sizeof(List) * TableSize);
if (hTable->Thelists == NULL)
{
printf("HashTable malloc error\n");
free(hTable);
return NULL;
}
/* 为Hash 桶对应的指针数组初始化链表节点 */
for (i = 0; i < TableSize; i++)
{
hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
if (hTable->Thelists[i] == NULL)
{
printf("HashTable malloc error\n");
free(hTable->Thelists);
free(hTable);
return NULL;
}
else
{
memset(hTable->Thelists[i], 0, sizeof(ListNode));
}
}
return hTable;
}
void Insert(HashTable* HashTable, int key, void* value)
{
element e = NULL, tmp = NULL;
List L = NULL;
e = Find(HashTable, key);
if (e == NULL)
{
tmp = (element)malloc(sizeof(ListNode));
if (tmp == NULL)
{
printf("malloc error\n");
return;
}
L = HashTable->Thelists[Hash(key, HashTable->TableSize)];
tmp->data = value;
tmp->key = key;
tmp->next = L->next;
L->next = tmp;
}
else
{
printf("the key already exist\n");
}
}
void Delete(HashTable* HashTable, int key)
{
element e = NULL, last = NULL;
List L = NULL;
int i = Hash(key, HashTable->TableSize);
L = HashTable->Thelists[i];
last = L;
e = L->next;
while (e != NULL && e->key != key)
{
last = e;
e = e->next;
}
if (e) /* 如果键值存在 */
{
last->next = e->next;
delete(e);
}
}
element Find(HashTable* HashTable, int key)
{
int i = 0;
List L = NULL;
element e = NULL;
i = Hash(key, HashTable->TableSize);
L = HashTable->Thelists[i];
e = L->next;
while (e != NULL && e->key != key)
{
e = e->next;
}
return e;
}
void* Retrieve(element e)
{
return e ? e->data : NULL;
}
void Destory(HashTable* HashTable)
{
int i = 0;
List L = NULL;
element cur = NULL, next = NULL;
for (i = 0; i < HashTable->TableSize; i++)
{
L = HashTable->Thelists[i];
cur = L->next;
while (cur != NULL)
{
next = cur->next;
free(cur);
cur = next;
}
free(L);
}
free(HashTable->Thelists);
free(HashTable);
}
int main()
{
const char* elems[] = { "翠花","小芳","苍老师" };
int i = 0;
HashTable* HashTable;
HashTable = InitHash(31);
Insert(HashTable, 1, (char *)elems[0]);
Insert(HashTable, 2, (char*)elems[1]);
Insert(HashTable, 3, (char*)elems[2]);
Delete(HashTable, 1);
for (i = 0; i < 4; i++)
{
element e = Find(HashTable, i);
if (e)
{
printf("%s\n", (const char*)Retrieve(e));
}
else
{
printf("Not found [key:%d]\n", i);
}
}
system("pause");
return 0;
}
运行环境: vs2019
运行结果:
结语:
学到的知识要, 多复习, 多总结, 多敲. 需要时间的积累, 才能引起质的改变. 自己写不出来的永远是别人的.
分享一下我的技巧: 代数法把具体的数字带进去, 看看能能能找到规律(掌握思想).
还有就是画图, 也很重要. 用笔画出来, 把数代进去, 方法虽然笨, 但真的很实用, 好记忆不如烂笔头!!! 还有多用debug(调试工具)
我是小白, C/C++功力…, 你懂得, 写的文章可能不是很好. 如果存在问题, 欢迎大神给予评判指正.
错了不可怕, 可怕的是找不出bug, 谁没错过!!!
最近学操作系统我认为, 学什么都要成本(时间), 即使它是免费的, 我个人认为要挑来学, 挑重点来学, 而不是从头到尾, 除非考试考研.
这个知识点我没有完全掌握, 就是会了也要复习, 革命尚未成功, 同志还需努力!!! , 我会回来反复复习的
今日是: 2020年5月21日, (由于疫情的原因)现在没有返校. 写博客,也可自己加强记忆,就当写写日记吧!!!
希望给个赞: 反正你又不亏, 顺便而已