#include <iostream>
#include <string>
#include <assert.h>
#include <Windows.h>
using namespace std;
#include <cstdlib> //*
#include <crtdbg.h> //*
#ifdef _DEBUG //*
#ifndef DBG_NEW //*
#define DBG_NEW new (_NORMAL_BLOCK, __FILE__, __LINE__)//*
#define new DBG_NEW //*
#endif //*
#endif
#define DEFAULT_LEN 5
typedef struct listNode_t {
int key; // 键值
void* date; // 数据域
struct listNode_t* next; // 链表的指针域
}*listP, listNode;
typedef listP ELEM; // 每个成员数据,和链表相似,通过结点操作
typedef listP LIST; // 用于创建一个关于索引的指针数组
typedef struct hashtable_t {
int table_len; // 哈希桶的个数有多少(哈希表的索引个数)
LIST* str; // 一个指针数组
}*hashP, hashNode;
// 初始化哈希表
bool
initHashTable(hashP& ht, int max_len = DEFAULT_LEN);
// 哈希函数,用于计算结点的索引,如果这个结点不存在就返回 -1 的索引(非法的)
static int
HASH(hashP ht, ELEM insert);
// 哈希表的插入,这里我们用前插法来实现(效率高)
bool
insertHashTable(hashP ht, ELEM insert);
// 哈希表的遍历
void
travelHashTable(hashP ht);
// 哈希表的删除
ELEM
deleteHashTable(hashP ht, const char* date = nullptr, int key = -1);
// 哈希表的销毁
void
destroyHashTable(hashP& ht);
int main(void)
{
string name[] = { "rock老师", "martin老师", "bingo老师", "libero","苍老师" };
hashP ht = nullptr;
// 哈希表的初始化
if (initHashTable(ht)) {
cout << "init success! " << endl;
}
// 哈希表的插入
ELEM insert = nullptr;
for (int i = 0; i < sizeof(name) / sizeof(name[0]); i++) {
insert = new listNode;
insert->key = i + 1;
insert->date = (void*)name[i].c_str();
if (insertHashTable(ht, insert)) {
printf_s("第 %d 个元素插入成功!, 它的key: %d date: %s \n", i + 1, insert->key, (const char*)insert->date);
}
else {
printf_s("第 %d 个元素插入失败!, 它的key: %d date: %s \n", i + 1, insert->key, (const char*)insert->date);
delete insert;
}
}
// 哈希表的遍历
travelHashTable(ht);
// 哈希表的删除
ELEM delnode = nullptr;
if (delnode = deleteHashTable(ht, "苍老师")) {
cout << "删除成功!" << endl;
delete delnode;
}else {
cout << "删除失败!" << endl;
}
// 哈希表的遍历
travelHashTable(ht);
cout << "destroyHashTable!" << endl;
destroyHashTable(ht);
cout << "destroyHashTable success! " << endl;
system("pause");
_CrtDumpMemoryLeaks();
return 0;
}
bool
initHashTable(hashP& ht, int max_len)
{
ht = new hashNode;
if (!ht) {
cerr << "the hashtable create error!" << endl;
return false;
}
// 如果传入的值比默认的参数还要大
max_len > DEFAULT_LEN ? ht->table_len = max_len : ht->table_len = DEFAULT_LEN;
ht->str = (LIST*)calloc(ht->table_len, sizeof(LIST));
if (!ht->str) {
cerr << "the ht->str create error!" << endl;
return false;
}
for (auto tmp = 0; tmp < ht->table_len; ) {
ht->str[tmp] = new listNode;
if (!ht->str[tmp]) continue; // 如果失败了重新再开
ht->str[tmp]->key = tmp; // 把键值先赋值
ht->str[tmp]->date = nullptr; // 把数据域的指针默认搞为空
ht->str[tmp]->next = nullptr; // 把指针域设置为空
tmp++;
}
return true;
}
static inline int
HASH(hashP ht, ELEM insert)
{
return insert ? insert->key % ht->table_len : -1;
}
bool
insertHashTable(hashP ht, ELEM insert)
{
if (!ht || !insert)return false;
int index = HASH(ht, insert); // 如果 insert 不存在
ELEM tmp = ht->str[index]->next;
while (tmp) {// 寻找该键是否已经存在,把这个去掉的话 就可以出项键值相同的元素
if (tmp->key == insert->key) {
break;
}
tmp = tmp->next;
}
if (tmp) {// 如果存在相同的键值,就不用插入了
cout << "the key of insert is exist!" << endl;
return false;
}
insert->next = ht->str[index]->next; // 前插法
ht->str[index]->next = insert;
return true;
}
void
travelHashTable(hashP ht)
{
if (!ht) {
cout << "hashtable is no exist!" << endl;
return;
}
cout << "********************************" << endl;
int count = 0;
while (count < ht->table_len) {
auto tmp = ht->str[count]->next;
while (tmp) {
printf_s("key:%d, date:%s ", tmp->key, (const char*)tmp->date);
tmp = tmp->next;
}
cout << endl;
count++;
}
cout << "********************************" << endl;
return;
}
ELEM // 软件工程的思想,在哪里申请的内存,最好就在那个函数中释放
deleteHashTable(hashP ht, const char* date, int key)
{
if (!ht) {
cout << "the hashtable is no exist !" << endl;
return nullptr;
}
char flag = 'f';
if (key < 0) {// date的与之类似 我就不写了 这里纯属考虑实际情况那些输入输出找茬的用户
int tmp = 0;
again_1:
printf_s("请输入要删除结点的键值 范围在 %d ~ %d 之间 \n", 0, ht->table_len - 1);
cin >> tmp;
if (tmp > ht->table_len - 1 || tmp < 0) {
cerr << "该键值是非法的" << endl;
again_2:
cout << "是否继续删除?y/n" << endl;
cin >> flag;
switch (flag)
{
case 'y':
goto again_1;
break;
case 'n':
return nullptr; // 如果放弃删除就直接推出了
default:
goto again_2;
}
}
key = tmp;
}
// 先找到要删除的那个键
int index = key % ht->table_len;
ELEM last = ht->str[index]; // 找上一个结点,以便删除
ELEM tmp_1 = ht->str[index]->next;
int maxlen = 0;
while (tmp_1) {
strlen((const char*)(tmp_1->date)) > strlen(date)
? maxlen = strlen((const char*)(tmp_1->date)) : maxlen = strlen(date);
if (strncmp((const char*)(tmp_1->date), date, maxlen) == 0) {
break;
}
last = tmp_1;
tmp_1 = tmp_1->next;
}
if (!tmp_1) return nullptr;
last->next = tmp_1->next;
return tmp_1;
}
void
destroyHashTable(hashP& ht)
{
if (!ht)return;
ELEM tmp_2 = nullptr;
for (int i = 0; i < ht->table_len; i++) {
auto tmp_1 = ht->str[i];
while (tmp_1) {
tmp_2 = tmp_1;
tmp_1 = tmp_1->next;
delete tmp_2;
}
}
delete[] ht->str;
delete ht;
return;
}
HashTable的代码实现
猜你喜欢
转载自blog.csdn.net/qq_44065088/article/details/102771819
今日推荐
周排行