什么是哈希表
哈希表有称为散列表,是一种空间换结构的数据结构。为每个数据加入键元素,通过键进行检索。
哈希表的组成:
键(key):是自己添加的用于检索的数据,一般为整型,也可以为其他类型;
值(value):用于存储数据的地方;
索引:数组的下标;
哈希桶:连接在哈希表数组上的数组或链表;
哈希函数:将键值映射到索引上(数组下标),一般采用求余法;
如图:
过程:建立结构体,把数据加上键,键通过对求余,判断和哪个数组下标一致,就链接到哪个下标,这个过程称为映射。通过映射,当我们要寻找这个数据时,提供键值,一求余,就可以求出在哪个哈希桶,然后挨个检索,就可以迅速找到。(当哈希通的数量越多,检索的速度越快)。
注哈希桶的实现也可以用顺序表。
哈希表的代码实现
#include<iostream>
#include<Windows.h>
#include<string.h>
using namespace std;
#define MAX_SIZE 16
typedef char* TYPE;
typedef struct _HashNode{
_HashNode* next;
TYPE data;
int key;
}HashNode;
typedef HashNode* HashList;
typedef struct _HashTable {
HashList HList;
int Hash_size;
}HashTable;
static int debug = 0;
//求出每个节点对应的 位置
int Hash(int key,int max_size) {
return (key % max_size);
}
//初始化哈希表
bool initHash(HashTable *Hash_T, int max_size) {
if (Hash_T == NULL) {
cout << "传入地址为空,无法初始化!" << endl;
return false;
}
Hash_T->Hash_size = max_size;
if (max_size <= 0) {
Hash_T->Hash_size = MAX_SIZE;
}
Hash_T->HList = new HashNode[Hash_T->Hash_size];
if (Hash_T->HList == NULL) {
cout << "分配内存出现错误!" << endl;
return false;
}
for (int i = 0; i < Hash_T->Hash_size; i++) {
Hash_T->HList[i].data = 0;
Hash_T->HList[i].key = 0;
Hash_T->HList[i].next = NULL;
}
return true;
}
//在哈希表中查找指定键是否存在
HashNode* find(HashTable *Hash_T, int key) {
HashNode *HN;
int e = 0;
if (Hash_T == NULL) {
cout << "传入地址为空,无法操作!" << endl;
return false;
}
if (key < 0) {
cout << "非合法键值,无法查找!" << endl;
return false;
}
e = Hash(key, Hash_T->Hash_size);
if (Hash_T->HList[e].next == NULL) {
return NULL;
}
else {
HN = Hash_T->HList[e].next;
}
do{
if (HN->key == key) {
return HN;
}
if (HN->next == NULL) {
break;
}
HN = HN->next;
} while (1);
return NULL;
}
//向指定哈希表中插入数据
bool insert(HashTable *Hash_T, int key, void *elem) {
int e = 0;
int a = 0;
if (Hash_T == NULL) {
cout << "传入地址为空,无法操作!" << endl;
return false;
}
if (key < 0) {
cout << "非合法键值,无法插入!" << endl;
return false;
}
if (find(Hash_T, key)) {
cout << "Hash表中已经此键!" << endl;
return false;
}
HashNode* HN = new HashNode();
HN->data = (const TYPE)elem;
HN->key = key;
e = Hash(key, Hash_T->Hash_size);
if (debug) {
cout << "e为:" << e << endl;
cout << "插入的键为:" << HN->key << " 插入的数据为:" << HN->data << endl;
}
if (Hash_T->HList[e].next==NULL) {
Hash_T->HList[e].next = HN;
HN->next = NULL;
if (debug) {
cout << "insert:";
cout << "插入的键为:" << (Hash_T->HList[e]).next->key << " 插入的数据为:" << Hash_T->HList[e].next->data << endl;
}
return true;
}
HN->next = Hash_T->HList[e].next;
Hash_T->HList[e].next = HN;
return true;
}
//删除哈希表根据键指定的元素
bool DeleteElems(HashTable *Hash_T, int key) {
if (Hash_T == NULL) {
cout << "传入地址为空,无法操作!" << endl;
return false;
}
if (key < 0) {
cout << "非合法键值,无法删除!" << endl;
return false;
}
if (find(Hash_T, key)) {
/*int a = 0;*/
HashNode *HN;
HashNode *HH;
int e = 0;
e = Hash(key, Hash_T->Hash_size);
HN = Hash_T->HList[e].next;
HH = &(Hash_T->HList[e]);
if (debug) {
cout << "find——e=" << e << endl;
}
while (1)
{
if (HN->key == key) {
if (HN->next == NULL) {
delete HN;
HH->next = NULL;
return true;
}
else
{
HH->next = HN->next;
delete HN;
return true;
}
}
HH = HN;
HN = HN->next;
}
return false;
}
else {
cout << "没有找到对应要删除的键,操作失败!" << endl;
return false;
}
}
//删除哈希表
bool DeleteHash(HashTable *Hash_T) {
HashNode* HN;
HashNode* HH;
if (Hash_T == NULL) {
cout << "传入地址为空,无法操作!" << endl;
return false;
}
for (int i = 0; i < Hash_T->Hash_size; i++) {
HN = &(Hash_T->HList[i]);
do{
HH = HN;
if (HH == NULL) {
break;
}
HN = HN->next;
delete HH;
} while (1);
}
delete Hash_T;
return true;
}
void* GetData(HashNode* e) {
if (e == NULL) {
cout << "传入的节点地址为空,无法查找" << endl;
return NULL;
}
return e->data;
}
int main() {
HashTable Hash_;
initHash(&Hash_, 6);
const char* arry[] = { "张三","李四","翠花" };
insert(&Hash_, 3, (void *)arry[0]);
insert(&Hash_, 4, (void *)arry[1]);
insert(&Hash_, 5, (void *)arry[2]);
DeleteElems(&Hash_, 3);
HashNode* e;
for (int i = 0; i < 6; i++) {
e = find(&Hash_, i);
if (debug) {
if (e) {
cout << "外e:" << e->key << endl;
}
}
if (e) {
printf("%s\n", GetData(e));
}
else {
printf("not found(key:%d)\n", i);
}
}
system("pause");
}