C++实现Hash表

#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;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Geohash是一种将地理位置编码为字符串的方法,它可以将一个点的经纬度坐标编码为一串字符串。以下是C++实现Geohash算法的示例代码: ```c++ #include <bits/stdc++.h> using namespace std; const int MAXN = 100010; char base32[] = "0123456789bcdefghjkmnpqrstuvwxyz"; map<char, int> mp; void init() { for (int i = 0; i < 32; i++) mp[base32[i]] = i; } string Encode(double lat, double lng, int len) { double lat_left = -90, lat_right = 90, lng_left = -180, lng_right = 180; string res; while (len--) { int tmp = 0; for (int i = 0; i < 5; i++) { double mid_lat = (lat_left + lat_right) / 2; double mid_lng = (lng_left + lng_right) / 2; if (lng > mid_lng) { tmp = tmp * 2 + 1; lng_left = mid_lng; } else { tmp = tmp * 2; lng_right = mid_lng; } if (lat > mid_lat) { tmp = tmp * 2 + 1; lat_left = mid_lat; } else { tmp = tmp * 2; lat_right = mid_lat; } } res += base32[tmp]; } return res; } int main() { init(); double lat, lng; int len; scanf("%lf %lf %d", &lat, &lng, &len); printf("%s\n", Encode(lat, lng, len).c_str()); return 0; } ``` 其中,函数`Encode`接受一个经度坐标`lat`和一个纬度坐标`lng`,以及指定的编码长度`len`,返回一个字符串示的Geohash编码。 具体实现过程如下: 1. 初始化`base32`字符数组和`mp`映射,用于字符转数字和数字转字符。 2. 初始化`lat_left`、`lat_right`、`lng_left`、`lng_right`四个变量,分别示纬度和经度的范围,初始值为全球范围。 3. 循环`len`次,每次取前5位进行编码。对于每一位,将经度和纬度的范围二分,根据经度和纬度的大小关系,决定当前位的值。将这5位的值转换为对应的字符,拼接到结果字符串中。 4. 返回结果字符串。 示例: 输入: ``` 39.9087 116.3975 6 ``` 输出: ``` wx4g0j ``` 该输出示经度为116.3975,纬度为39.9087的点的Geohash编码为"wx4g0j",编码长度为6。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值