#pragma once
#include <string>
using namespace std;
#define TABLE_LEN 8
class CHashTable
{
private:
// 定义节点类型
typedef struct tagNode {
// 构造 传入 key 和 val 默认一下个节点为null
tagNode(string key, string val, tagNode* pNext = nullptr) :
m_key(key), m_val(val), m_pNext(pNext) {};
string m_key; // 保存的key
string m_val; // 保存的数据
tagNode* m_pNext; // 下一个节点的地址
}NODE,*PNODE;
public:
CHashTable();
~CHashTable();
CHashTable(const CHashTable &obj);
CHashTable& operator=(const CHashTable& obj);
// 操作
// 增加
bool Insert(string key, string val);
// 删除
bool Delete(string key);
// 查询
bool Find(string key);
// 修改 根据key 返回引用 可以直接修改
string& operator[](string key);
private:
// 初始化函数
void Init();
// 查找节点
PNODE FindNode(string key);
private:
/*
定义一个这种节点的数组
每一个元素都是一个节点
每一个节点又可以变为一个链表
*/
PNODE m_ary[TABLE_LEN];
};
#include "CHashTable.h"
#include <functional> // 引入c++的 hash函数
using namespace std;
CHashTable::CHashTable()
{
Init();
}
CHashTable::~CHashTable()
{
}
CHashTable::CHashTable(const CHashTable& obj)
{
// 在进行拷贝构造之前也先进行初始化
Init();
}
CHashTable& CHashTable::operator=(const CHashTable& obj)
{
if (this == &obj) return *this;
return *this;
}
/*
初始化函数
*/
void CHashTable::Init()
{
memset(this->m_ary, 0, sizeof(this->m_ary));
}
/*
根据key和val完成插入
*/
bool CHashTable::Insert(string key, string val)
{
/*
根据key计算哈希
告诉hash函数我们需要对字符串进行hash运算
并把运算后的hash结果保存到str_hash中
*/
size_t str_hash = hash<string>{}(key);
// 计算出来的hash值 还要跟数组进行取余
size_t index = str_hash % TABLE_LEN;// 这样就可以保证是在数组的索引中
// 创建一个节点
PNODE pNewNode = new NODE(key,val);
// 如果创建失败
if(pNewNode == nullptr){
return false;
}
// 判断当前位置是否已经有元素存在
/*
if (this->m_ary[index] == nullptr) {
// 如果没有就直接放进去 作为第一个节点
this->m_ary[index] = pNewNode;
return;
}
*/
// 否则就是已经有元素存在了 遍历
// PNODE pNode = this->m_ary[index]; // 获取第一个头节点元素
// 新节点作为头部
pNewNode->m_pNext = this->m_ary[index];
this->m_ary[index] = pNewNode;
/*
// 使用头插法
pNewNode->m_pNext = pNode->m_pNext;
pNode->m_pNext = pNewNode;
*/
/*
while (pNode->m_pNext != nullptr) {
// 如果还有下一个元素的话
pNode = pNode->m_pNext;
}
// 遍历结束找到最后一个了 插入到最后
pNode->m_pNext = pNewNode;
*/
return true;
}
/*
根据key删除
*/
bool CHashTable::Delete(string key)
{
size_t str_hash = hash<string>{}(key);
// 计算出来的hash值 还要跟数组进行取余
size_t index = str_hash % TABLE_LEN;// 这样就可以保证是在数组的索引中
// 同样计算出来hash
PNODE pNode = this->m_ary[index];
if(pNode == nullptr){
// 如果为空 证明这个元素的链表为空
return false;
}
// 判断是不是第一个
if (pNode->m_key == key){
// 第一个的话直接删除
this->m_ary[index] = pNode->m_pNext;
return true;
}
// 如果不为空 并且不是第一个 遍历删除
PNODE pPreNode = pNode; // 记录前一个
while(pNode->m_pNext != nullptr){
if (pNode->m_pNext->m_key == key){
/*
上一个节点 跳过当前节点
*/
pPreNode->m_pNext = pNode->m_pNext->m_pNext;
delete pNode->m_pNext;
return true;
}
// 循环后移
pPreNode = pNode;
pNode = pNode->m_pNext;
}
// 遍历完了 那就是没找到
return false;
}
/*
根据key查询
*/
bool CHashTable::Find(string key)
{
if (FindNode(key)) return true;
return false;
}
/*
查找节点
*/
CHashTable::PNODE CHashTable::FindNode(string key)
{
size_t str_hash = hash<string>{}(key);
// 计算出来的hash值 还要跟数组进行取余
size_t index = str_hash % TABLE_LEN;// 这样就可以保证是在数组的索引中
// 同样计算出来hash
PNODE pNode = this->m_ary[index];
if (pNode == nullptr) {
// 如果为空 证明这个元素的链表为空
return nullptr;
}
// 判断是不是第一个
if (pNode->m_key == key) {
// 如果是第一个的话 直接return
return pNode;
}
// 如果不为空 并且不是第一个 遍历查找
PNODE pPreNode = pNode; // 记录前一个
while (pNode->m_pNext != nullptr) {
if (pNode->m_pNext->m_key == key) {
// 如果找到了
return pNode->m_pNext;
}
// 循环后移
pPreNode = pNode;
pNode = pNode->m_pNext;
}
// 遍历完了 那就是没找到
return nullptr;
}
/*
根据key找到元素返回引用给外部修改
*/
string& CHashTable::operator[](string key)
{
auto pNode = FindNode(key);
if(pNode != nullptr){
return pNode->m_val;
}
// 没有插入新的然后返回新的给他
Insert(key,string());
return FindNode(key)->m_val;
}
#include <iostream>
#include <Windows.h>
#include "CHashTable.h"
using namespace std;
int main()
{
CHashTable hashTable;
hashTable.Insert("star","zjx");
hashTable.Insert("starstar","zjx");
hashTable.Insert("zjx","star");
hashTable.Insert("小红","密码123456");
hashTable.Insert("小绿","密码56465465456");
hashTable.Insert("小黄","密码53121986415");
hashTable.Insert("小白","密码23196453211");
hashTable.Insert("小明","密码77641532561");
hashTable.Insert("0小红0", "密码123456");
hashTable.Insert("0小绿0", "密码56465465456");
hashTable.Insert("0小黄0", "密码53121986415");
hashTable.Insert("0小白0", "密码23196453211");
hashTable.Insert("0小明0", "密码77641532561");
bool ret = hashTable.Delete("zjx");
ret = hashTable.Delete("0小红0");
ret = hashTable.Delete("tang"); // false 不给你删
cout << hashTable.Find("0小明0") << endl;
cout << hashTable.Find("tang") << endl;
system("pause");
return 0;
}