散列 - 分离链接法
通过某种特定的函数/算法(称为散列函数/算法)将要检索的项与用来检索的索引(称为散列,或者散列值)关联起来,生成一种便于搜索的数据结构(称为散列表)。也译为散列。
我们需要将输入的字符串进行转换, 将其转换成数字, 在插入保存的数, 当然, 也可能会存在不同字符串对应相同的数字, 这时, 为了保证不冲突, 我们将字符串对应相同的数字用链表表示, 用链表保存我们要存储的东西. 字符串是钥匙, 只能打开对应的箱子, 而箱子里也有其他物品, 我们在搜索箱子就能找到我们想要的
//HashTbld代表的是钥匙, 而ListNode代表的是物品, 因为有多个钥匙, 所以HashTbl我们用数组链表表示
struct ListNode;
struct HashTbl;
typedef struct ListNode *Position;
typedef struct HashTbl *HashTabl;
const int N = 10;
struct ListNode
{
char *ch;
Position next;
};
struct HashTbl
{
int The_SIZE;
Position *The_ListNode;
};
字符串转换
unsigned int Hash(char *key, int SIZE)
{
unsigned int HashSIZE = 0;
while (*key != '\0')
HashSIZE = (HashSIZE << 5) + *key++;
return HashSIZE % SIZE;
}
初始化钥匙跟箱子, 跟链表初始化一样的, 差别只是在于对HashTbl的初始化是数组
void Creat(int SIZE, HashTabl &H)
{
//初始化HashTbl
H = (HashTabl)malloc(sizeof(struct HashTbl));
if (H == NULL)
exit(0);
H->The_SIZE = SIZE;
//初始化HashTbl的数组, 即初始化钥匙
H->The_ListNode = (Position *)malloc(sizeof(Position) * SIZE);
if (H->The_ListNode == NULL)
exit(0);
for (int i = 0; i < SIZE; i++)
{
//对每个数组的链表初始化, 也就是初始化箱子
H->The_ListNode[i] = (Position)malloc(sizeof(struct ListNode));
if (H->The_ListNode[i] == NULL)
exit(0);
H->The_ListNode[i]->next = NULL;
}
}
对于初入与删除, 就像链表的插入跟删除一样, 唯一不同的是, 插入(放物品)我们需要计算他的位置, 需要用Hash计算来找到位置(找到他的钥匙, 才能确定放的对应的宝箱), 找到用链表插入的方式, 将他插入链表即可, 删除也一样
void Inset(HashTabl H, char *key)
{
if (!Find(H, key))
{
Position L, temp;
temp = (Position)malloc(sizeof(struct ListNode));
if (temp == NULL)
exit(0);
//找到对应的钥匙
L = H->The_ListNode[Hash(key, H->The_SIZE)];
//插入, 放入宝箱中
temp->ch = key;
temp->next = L->next;
L->next = temp;
}
}
//删除
void Dele(HashTabl H, char *key)
{
if (Find(H, key))
{
//找到钥匙
Position P, L;
P = H->The_ListNode[Hash(key, H->The_SIZE)];
//宝箱中查找我们要的物品, 即搜寻链表
while (P->next != NULL && P->next->ch != key)
P = P->next;
L = P->next;
P->next = L->next;
}
}
源代码
#include <stdio.h>
#include <stdlib.h>
struct ListNode;
struct HashTbl;
typedef struct ListNode *Position;
typedef struct HashTbl *HashTabl;
const int N = 10;
struct ListNode
{
char *ch;
Position next;
};
struct HashTbl
{
int The_SIZE;
Position *The_ListNode;
};
//初始化钥匙跟箱子
void Creat(int SIZE, HashTabl &H)
{
//初始化HashTbl
H = (HashTabl)malloc(sizeof(struct HashTbl));
if (H == NULL)
exit(0);
H->The_SIZE = SIZE;
//初始化HashTbl的数组, 即初始化钥匙
H->The_ListNode = (Position *)malloc(sizeof(Position) * SIZE);
if (H->The_ListNode == NULL)
exit(0);
for (int i = 0; i < SIZE; i++)
{
//对每个数组的链表初始化, 也就是初始化箱子
H->The_ListNode[i] = (Position)malloc(sizeof(struct ListNode));
if (H->The_ListNode[i] == NULL)
exit(0);
H->The_ListNode[i]->next = NULL;
}
}
//字符串转换
unsigned int Hash(char *key, int SIZE)
{
unsigned int HashSIZE = 0;
while (*key != '\0')
HashSIZE = (HashSIZE << 5) + *key++;
return HashSIZE % SIZE;
}
Position Find(HashTabl H, char *key)
{
Position P;
P = H->The_ListNode[Hash(key, H->The_SIZE)];
while (P != NULL && P->ch != key)
P = P->next;
return P;
}
//对于初入与删除, 就像链表的插入跟删除一样, 唯一不同的是, 插入(放物品)我们需要计算他的位置,
//需要用Hash计算来找到位置(找到他的钥匙, 才能确定放的对应的宝箱), 找到用链表插入的方式,
//将他插入链表即可, 删除也一样
void Inset(HashTabl H, char *key)
{
if (!Find(H, key))
{
Position L, temp;
temp = (Position)malloc(sizeof(struct ListNode));
if (temp == NULL)
exit(0);
//找到对应的钥匙
L = H->The_ListNode[Hash(key, H->The_SIZE)];
//插入, 放入宝箱中
temp->ch = key;
temp->next = L->next;
L->next = temp;
}
}
//删除
void Dele(HashTabl H, char *key)
{
if (Find(H, key))
{
//找到钥匙
Position P, L;
P = H->The_ListNode[Hash(key, H->The_SIZE)];
//宝箱中查找我们要的物品, 即搜寻链表
while (P->next != NULL && P->next->ch != key)
P = P->next;
L = P->next;
P->next = L->next;
}
}
int main()
{
HashTabl H = NULL;
int SIZE = 10, i;
Creat(SIZE, H);
char key[10];
for (i = 0; i < SIZE; i++)
{
scanf("%s", key);
Inset(H, key);
}
scanf("%s", key);
Dele(H, key);
scanf("%s", key);
Position t = Find(H, key);
printf("%s", t->ch);
system("pause");
return 0;
}