哈希表C/C++代码实现

哈希表
散列表,它是基于快速存取的角度设计的,也是一种典型的 “空间换时间” 的做法;
键(key) : 组员的编号, 如: 1,2,3…;
值(value): 组员的其他信息 (包含: 性别, 年龄, 战斗力等);
索引: 数组的下标 (0,1,2…), 用以快速定位和检索数据;
哈希桶: 保存索引的数组 (链表或数组), 数组成员为每一个索引值相同的多个元素
哈希函数: 将组员编号映射到索引上, 采用求余法(方法可以有很多种);
算法代码实现:(使用的是链表实现)

#include <iostream>
#include <string>

using namespace std;

#define DEFAULT_SIZE 32

//哈希表元素定义
typedef struct _listNode {
	struct _listNode* next;//指像下一个位置的指针
	int key;//索引编号
	void* data;//保存的数据
}listNode;

typedef listNode* list;
typedef listNode* elem;

//哈希表结构定义
typedef struct _HashTable {
	int TableSize;//哈希桶的总个数
	list* Thelists;//保存在链表的位置
}HashTable;

//哈希函数: 根据key 计算索引,定位Hash桶的位置
int Hash(int key, int TableSize) {
	return (key % TableSize);
}

//初始化哈希表
HashTable* initHash(int TableSize) {
	if (TableSize <= 0) {
		TableSize = DEFAULT_SIZE;
	}

	HashTable* htable = NULL;
	htable = new HashTable;
	if (htable == NULL) {
		cout << "htable new error!" << endl;
		return NULL;
	}
	htable->TableSize = TableSize;

	//为hash桶分配内存空间,其为一个指针数组
	htable->Thelists = new list[htable->TableSize];//这里需要分配一个指针数组
	if (htable->Thelists == NULL) {
		cout << "list new error!" << endl;
		delete htable;
		return NULL;
	}

	//为hash桶对应的指针数组初始化链表节点
	for (int i = 0; i < TableSize; i++) {
		htable->Thelists[i] = (list)(new listNode);//需要把分配的节点进行类型转换
		if ((list)htable->Thelists[i]==NULL) {
			cout << "listNode new error!" << endl;
			delete htable->Thelists;
			delete htable;
			return NULL;
		}
		else {
			//初始化hash桶里的所有元素为0
			memset(htable->Thelists[i], 0, sizeof(listNode));
		}
	}

	return htable;
}

//从哈希表中根据键值查找元素
elem Find(HashTable* table, int key) {
	list L = NULL;
	elem e = NULL;
	int i = 0;
	i = Hash(key, table->TableSize);
	L = table->Thelists[i];
	e = L->next;

	while (e != NULL && e->key != key) {
		e = e->next;
	}

	return e;
}

//哈希表链表插入元素,元素为键值对
void insertHash(HashTable* table, int key, void* value) {
	elem e = NULL;
	elem tmp = NULL;
	list L = NULL;

	e = Find(table, key);

	if (e == NULL) {
		tmp = new listNode;
		if (tmp == NULL) {
			cout << "tmp new error!" << endl;
			return;
		}

		//使用前插法
		L = table->Thelists[Hash(key,table->TableSize)];
		tmp->data = value;
		tmp->key = key;
		tmp->next = L->next;
		L->next = tmp;
	}
	else {
		cout << "key already exist!" << endl;
	}
}

//哈希表链表删除元素
void deleteHash(HashTable* table, int key) {
	elem e = NULL;
	elem last = NULL;
	list L = NULL;

	int i = Hash(key, table->TableSize);
	L = table->Thelists[i];

	last = L;
	e = L->next;
	while (e != NULL && e->key != key) {
		e = e->next;
		last = e;
	}

	if (e != NULL) {
		//如果键值对存在
		last->next = e->next;
		delete e;
	}
}

//提取哈希表中的数据
void *retrieveHash(elem e) {
	return e ? e->data : NULL;
}

//销毁哈希表
void destoryHash(HashTable* hash) {
	list L = NULL;
	elem cur = NULL;
	elem next = NULL;

	for (int i = 0; i < hash->TableSize; i++) {
		L = hash->Thelists[i];
		cur = L->next;

		while (cur != NULL) {
			next = cur->next;
			delete cur;
			cur = next;
		}

		delete L;
	}

	delete hash->Thelists;
	delete hash;
}

//测试代码
int main(void) {

	const char* elems[] = { "小王","老王","老宋"};

	HashTable* hash;
	hash = initHash(16);
	
	insertHash(hash, 1, (char*)elems[0]);
	insertHash(hash, 2, (char*)elems[1]);
	insertHash(hash, 3, (char*)elems[2]);

	deleteHash(hash, 1);

	for (int i = 1; i < 4; i++) {
		elem e = Find(hash, i);

		if (e != NULL) {
			cout << "NO."<<i<<" is:"<<(const char*)retrieveHash(e) << endl;
		}
		else {
			cout << "not seek out:"<<elems[i-1] << endl;
		}
	}

	system("pause");
	return 0;
}

在这里插入图片描述
小练习:
DNA 检测字串匹配
测试色盲的基因组包含 8 位基因,编号 1 至 8。每一位基因都可以用一个字符来表示,这个字符 是’A’、‘B’、‘C’、'D’四个字符;
解答思路:

  1. 可以直接把待测试基因的 2,3,4,5 位直接与基因库里的记录逐一对比,但如果色盲基因库很庞 大,程序执行效率很低
  2. 可以使用哈希表来存储色盲基因库数据,通过哈希函数把 4 位色盲基因映射到哈希表中,大大提高检索的效 率.
#pragma once
#ifndef DNA_HASH_H
#define DNA_HASH_H
#include <iostream>
#include <string>

using namespace std;

#define DEFAULT_SIZE 32
#define H_int32 int

//定义哈希表的元素结构
typedef struct _listNode {
	struct _listNode* next;
	void* key;
	void* data;
}listNode;

typedef listNode* list;
typedef listNode* Elem;

typedef struct _HashTable {
	int TableSize;
	list* Thelists;
}Hash;

//哈希函数
H_int32 Hash_Func(void* key, H_int32 TableSize);

//初始化哈希表
Hash* initHash(H_int32 TableSize);

//哈希表插入元素和键值对
void insertHash(Hash* hash, void* key, void* value);

//哈希表删除元素,元素为键值对
void deleteHash(Hash* hash, void* key);

//哈希表查找
Elem FindHash(Hash* hash, void* key);

//哈希表销毁
void destotyHash(Hash* hash);

//哈希表元素中提取数据
void* retrieveHash(Elem elem);

#endif // !DNA_HASH_H
#include "DNA_hash.h"

#define BUCKET_SIZE 1024

#define compare(a,b)  strcmp((const char*)a,(const char*)b)

#define hash_func      SDDMhash

unsigned int SDDMhash(void* key) 
{
	unsigned int hash = 0;
	char* str = (char*)key;

	while (*str) {
		hash = (*str++) + (hash << 6) + (hash << 16) - hash;
	}

	return (hash & 0x7FFFFFFF);
}
H_int32 Hash_Func(void* key, H_int32 TableSize)
{
	return hash_func(key)%TableSize;
}

Hash* initHash(H_int32 TableSize)
{
	Hash* hash = NULL;
	hash = new Hash;

	if (TableSize <= 0) {
		TableSize = DEFAULT_SIZE;
	}

	if (hash == NULL) {
		cout << "初始化内存分配失败!" << endl;
		return NULL;
	}
	hash->TableSize = TableSize;

	//为hash桶分配内存空间,其为一个指针数组
	//hash->Thelists = (list*)malloc(sizeof(list) * TableSize);
	hash->Thelists = new list[hash->TableSize];
	if (hash->Thelists == NULL) {
		cout << "数组指针内存分配失败!" << endl;
		delete hash;
		return NULL;
	}

	//为hash 桶对应的指针数组初始化链表节点
	for (int i = 0; i < TableSize; i++) {
		hash->Thelists[i] = (list) (new listNode);
		if ((list)hash->Thelists[i]==NULL) {
			cout << "指针数组内存分配失败!" << endl;
			delete hash;
			return NULL;
		}
		else{
			memset(hash->Thelists[i], 0, sizeof(list));
		}
	}

	return hash;
}

void insertHash(Hash* hash, void* key, void* value)
{
	Elem elem = NULL;
	Elem tmp = NULL;
	list L = NULL;

	elem = FindHash(hash, key);

	if (elem == NULL) {
		tmp = new listNode;
		if (tmp == NULL) {
			cout << "插入元素内存分配失败!" << endl;
			return;
		}

		H_int32 code = Hash_Func(key, hash->TableSize);
		L = hash->Thelists[code];//前插法
		tmp->data = value;
		tmp->key = key;
		tmp->next = L->next;
		L->next = tmp;
	}
	else {
		cout << "已存在的索引!" << endl;
	}
}

void deleteHash(Hash* hash, void* key)
{
	Elem elem = NULL;
	Elem last = NULL;
	list L = NULL;
	int i = Hash_Func(key, hash->TableSize);
	L = hash->Thelists[i];

	last = L;
	elem = L->next;
	while (elem != NULL && elem->key != key) {
		last = elem;
		elem = elem->next;
	}

	if (elem) {
		last->next = elem->next;
		delete elem;
	}
}

Elem FindHash(Hash* hash, void* key)
{
	list L = NULL;
	Elem elem = NULL;
	int i = 0;

	i = Hash_Func(key, hash->TableSize);
	L = hash->Thelists[i];
	elem = L->next;

	while (elem != NULL && compare(elem->key, key) != 0) {
		elem = elem->next;
	}

	return elem;
}

void destotyHash(Hash* hash)
{
	list L = NULL;
	Elem cur = NULL;
	Elem next = NULL;

	for (int i = 0; i < hash->TableSize; i++) {
		L = hash->Thelists[i];
		cur = L->next;

		while (cur != NULL) {
			next = cur->next;
			delete cur;
			cur = next;
		}

		delete L;
	}

	delete hash->Thelists;
	delete hash;
}

void* retrieveHash(Elem elem)
{
	return elem?elem->data:NULL;
}

int main(void) {

	const char* elems[] = { "ADBB","BDDC","CDBC","BDBB" };
	const char* tester = "ABDABACD";
	char cur[5] = { '\0' };

	Hash* hash = NULL;
	hash = initHash(BUCKET_SIZE);

	insertHash(hash, (int*)elems[0], (char*)elems[0]);
	insertHash(hash, (int*)elems[1], (char*)elems[1]);
	insertHash(hash, (int*)elems[2], (char*)elems[2]);
	insertHash(hash, (int*)elems[3], (char*)elems[3]);

	deleteHash(hash, (int*)elems[0]);

	strncpy_s(cur, tester + 1, 4);

	Elem elem = FindHash(hash, (char*)cur);
	if (elem) {
		cout <<"匹配到基因:"<< (char*)retrieveHash(elem) << endl;
	}
	else {
		cout << "没有找到匹配的基因!" << endl;
	}

	system("pause");
	return 0;
}

在这里插入图片描述
C++实现

#include<iostream>
#include<list>
#include<utility>//pair<>函数的头文件

using namespace std;

//为了兼容更多的数据使用泛型编程
template<class T>
class Hash_tab
{
public:
	Hash_tab(int length);//构造函数

	Hash_tab(const Hash_tab* h_t);//拷贝构造函数

	~Hash_tab();//析构函数

	T insert(int key, T val);//数据插入

	T remove_key(int key);//根据索引删除数据

	T remove_val(T val);//根据数据删除数据

	T find_key(int key);//根据索引查找数据

	int find_val(T val);//根据数据查找索引


	void print();//打印哈希表

private:

	//哈希函数,计算哈希桶的位置
	int hash_fun(int key) { return key % len; }

	int get_lenght() { return len; }

private:

	using ht = list<pair<int, T>>;//组合两个数据的链表节点
	int len;//哈希表的长度;
	ht* elem = NULL;
};

template<class T>
Hash_tab<T>::Hash_tab(int length):len(length)
{
	if (this->len <= 0) {
		this->len = 1;
	}
	//分配一个组合了两个数据的指针数组
	this->elem = new ht[len];
}

template<class T>
Hash_tab<T>::Hash_tab(const Hash_tab* h_t)
{
	this->elem = new ht[len];

	for (int i = 0; i < len; i++) {
		h_t->elem[i] = this->elem[i];
	}
}

template<class T>
Hash_tab<T>::~Hash_tab()
{
	if (elem != nullptr) {
		delete[]elem;
		elem = NULL;
	}
}

template<class T>
T Hash_tab<T>::insert(int key, T val)
{
	int place = this->hash_fun(key);

	for (auto& s : this->elem[place]) {//找到place在elem数组中的位置

		if (s.first == key) {//如果key这个索引已经存在有三种情况

			//1.返回原有的数据
			return s.second;

			//2.替换掉原有的数据
			//s.first = key;
			//s.second = val;
			//return val;

			//3.在后面继续插入
			//elem[place].push_back({key,val});
			//return val;
		}
	}

	elem[place].push_back({ key,val });

	return val;
}

template<class T>
T Hash_tab<T>::remove_key(int key)
{
	int place = this->hash_fun(key);

	for (auto& s : elem[place]) {
		if (s.first == key) {

			return s.second;
			elem[place].remove(s);
		}
	}

	return 0;
}

template<class T>
T Hash_tab<T>::remove_val(T val)
{
	for (int i = 0; i < len; i++) {
		for (auto& s : elem[i]) {
			if (s.second == val) {

				return s.second;

				elem[i].remove(s);
			}
		}
	}

	return NULL;
}

template<class T>
T Hash_tab<T>::find_key(int key)
{
	int base = this->hash_fun(key);

	for (auto& s : elem[base]) {
		if (s.first == key) {

			return s.second;
		}
	}

	return NULL;
}

template<class T>
int Hash_tab<T>::find_val(T val)
{
	for (int i = 0; i < len; i++) {
		for (auto& s : elem[i]) {
			if (s.second == val) {

				return s.first;
			}
		}
	}

	return 0;
}

template<class T>
void Hash_tab<T>::print()
{
	for (int i = 0; i < len; i++) {
		cout << "(" << i << ")->";
		for (auto& s : elem[i]) {
			cout << "[" << s.first << "," << s.second << "]->";
		}

		cout << "NULL" << endl;
	}
}



int main() {

	Hash_tab<string> s(0);

	s.insert(0, "张飞");
	s.insert(4, "刘备");
	s.insert(11,"鲁班");

	cout << s.find_key(0) << endl;
	cout << s.find_val("刘备") << endl;

	s.print();

	system("pause");
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以,下面是一个简单的哈希表实现的 C 代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #define TABLE_SIZE 10 typedef struct { char *key; int value; } Entry; typedef struct { Entry **entries; } HashTable; HashTable* createHashTable() { HashTable* hashTable = malloc(sizeof(HashTable)); hashTable->entries = calloc(TABLE_SIZE, sizeof(Entry*)); return hashTable; } int hashCode(char *key) { int hash = 0; for (int i = 0; i < strlen(key); i++) { hash += key[i]; } return hash % TABLE_SIZE; } void insert(HashTable* hashTable, char *key, int value) { int index = hashCode(key); Entry* entry = malloc(sizeof(Entry)); entry->key = strdup(key); entry->value = value; if (hashTable->entries[index] == NULL) { hashTable->entries[index] = entry; } else { // Handle collision: Linear probing int newIndex = (index + 1) % TABLE_SIZE; while (hashTable->entries[newIndex] != NULL) { newIndex = (newIndex + 1) % TABLE_SIZE; } hashTable->entries[newIndex] = entry; } } int get(HashTable* hashTable, char *key) { int index = hashCode(key); if (hashTable->entries[index] != NULL && strcmp(hashTable->entries[index]->key, key) == 0) { return hashTable->entries[index]->value; } else { // Handle collision int newIndex = (index + 1) % TABLE_SIZE; while (hashTable->entries[newIndex] != NULL && strcmp(hashTable->entries[newIndex]->key, key) != 0) { newIndex = (newIndex + 1) % TABLE_SIZE; } if (hashTable->entries[newIndex] != NULL && strcmp(hashTable->entries[newIndex]->key, key) == 0) { return hashTable->entries[newIndex]->value; } else { return -1; // Key not found } } } void freeHashTable(HashTable* hashTable) { for (int i = 0; i < TABLE_SIZE; i++) { if (hashTable->entries[i] != NULL) { free(hashTable->entries[i]->key); free(hashTable->entries[i]); } } free(hashTable->entries); free(hashTable); } int main() { HashTable* hashTable = createHashTable(); // Inserting values into hash table insert(hashTable, "apple", 5); insert(hashTable, "banana", 10); insert(hashTable, "orange", 15); // Getting values from hash table printf("Value for key 'apple': %d\n", get(hashTable, "apple")); printf("Value for key 'banana': %d\n", get(hashTable, "banana")); printf("Value for key 'orange': %d\n", get(hashTable, "orange")); printf("Value for key 'watermelon': %d\n", get(hashTable, "watermelon")); freeHashTable(hashTable); return 0; } ``` 这个代码使用了线性探测法来处理哈希冲突。在插入操作中,如果发生冲突,会往后查找空槽位,直到找到一个空槽位或者遍历完整个哈希表。在查找操作中,如果发生冲突,会往后查找直到找到对应的键或者遍历完整个哈希表。由于这只是一个简单的示例,所以哈希表的大小是固定的。在实际使用中,我们可能会采用更复杂的解决冲突的方法,并且根据需要动态调整哈希表的大小。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值