HashTable C++实现之分离链接法

 HashTable是以常数时间进行进行插入,删除和查找的数据结构。其查找原理是:通过哈希函数Hash(),进行哈希得到value,value为哈希表的下表。怎么能得到均衡的value呢?

Hash()(哈希一般是通过字符串映射到键值)

Index HashTable::Hash_one(const ElemType& key, const size_t tablesize)const {
	size_t hashval = 0;
	int i = 0;
	while (key[i] != '\0') {
		hashval += key[i];
		++i;
	}

	return hashval % tablesize;
}

Index HashTable::Hash_two(const ElemType& key, const size_t tablesize)const {
	auto hashval = key[0] + 27 * key[1] + 27 * 27 * key[2];
	return hashval % tablesize;
}

Index HashTable::Hash_three(const ElemType& key, const size_t tablesize)const {
	size_t hashval = 0;
	int i = 0;
	while (key[i] != '\0') {
		hashval = (hashval<<5) + key[i];
		++i;
	}

	return hashval % tablesize;
}

 经过测试只有Hash_Three()得到的键值是均衡分布的。

但有时候不同的字符串会映射到相同的键值,怎么解决这个问题呢?(我们也叫发生冲突)

方法一:分离链接法(数组和链表的组合实现)

 

全部源码如下:

#include<iostream>
#include<memory>
#include<vector>
typedef size_t Index;
typedef std::string ElemType;
typedef struct Listnode* List;
typedef struct Listnode* Position;
const size_t MaxSize = 11;
struct Listnode {
	ElemType  element;
	List      next;
};

struct HashTab {
	size_t    tablesize;
	List*     lists;
};

class HashTable {
public:
	HashTable() :hashtable(std::make_unique<HashTab>()) {
		hashtable->tablesize = MaxSize;
		hashtable->lists = new List[MaxSize]();

	}

	~HashTable() {
		if (hashtable->lists)
			delete[] hashtable->lists;
	}
public:
	Index Hash_one(const ElemType& key, const size_t tablesize)const;
	Index Hash_two(const ElemType& key, const size_t tablesize)const;
	Index Hash_three(const ElemType& key, const size_t tablesize)const;
public:
	Position Find(const ElemType key)const;
	void Insert(const ElemType key);
	void Delete(const ElemType key);
	void Display()const;

private:
	std::unique_ptr<HashTab>hashtable;
};

Index HashTable::Hash_one(const ElemType& key, const size_t tablesize)const {
	size_t hashval = 0;
	int i = 0;
	while (key[i] != '\0') {
		hashval += key[i];
		++i;
	}

	return hashval % tablesize;
}

Index HashTable::Hash_two(const ElemType& key, const size_t tablesize)const {
	auto hashval = key[0] + 27 * key[1] + 27 * 27 * key[2];
	return hashval % tablesize;
}

Index HashTable::Hash_three(const ElemType& key, const size_t tablesize)const {
	size_t hashval = 0;
	int i = 0;
	while (key[i] != '\0') {
		hashval = (hashval << 5) + key[i];
		++i;
	}

	return hashval % tablesize;
}

Position HashTable::Find(const ElemType key)const {
	auto p = hashtable->lists[Hash_three(key, hashtable->tablesize)];

	if (p != nullptr) {
		while (p != nullptr) {
			if (p->element == key)
				return p;
			p = p->next;
		}
	}
	return nullptr;
}

void HashTable::Insert(const ElemType key) {
	if (auto pos = Find(key))
		return;
	else {
		auto index = Hash_three(key,hashtable->tablesize);
		if (hashtable->lists[index] == nullptr) {
			hashtable->lists[index] = new Listnode;
			auto newnode = new Listnode;
			newnode->element = key;
			hashtable->lists[index] = newnode;
			newnode->next = nullptr;
		}
		else {
			auto newnode = new Listnode;
			newnode->element = key;
			auto L = hashtable->lists[index];
			newnode->next = L->next;
			L->next = newnode;
		}
	}
}

void HashTable::Delete(const ElemType key) {  /*Lazy Delete*/

	if (auto p = Find(key)) {
		auto index = Hash_three(key, hashtable->tablesize);
		auto l = hashtable->lists[index];
		if (l->next == nullptr)
			l->element = "";
		else {
			while (true) {
				if (l== p)
					break;
				l = l->next;
			}
			l->element = "";
		}

	}
	else
		return;
}

void HashTable::Display()const {
	for (int i = 0; i < hashtable->tablesize; ++i) {
		if (auto p = hashtable->lists[i]) {
			while (p != nullptr  ) {
				
				std::cout << "i: " << i << " " << p->element.c_str() << std::endl;
				p = p->next;
			}
		}
	}
}

int main(void)
{
	HashTable hash;
	const std::string name_one = "Jay";
	const std::string name_two = "Cry";
	const std::string name_three = "Cherry";
	const std::string name_four = "Yun";
	const std::string name_five = "Jerry";
	const std::string name_six = "Derty";
	const std::string name_seven = "Striy";
	const std::string name_eight = "Actry";
	hash.Insert(name_one);
	hash.Insert(name_two);
	hash.Insert(name_three);
	hash.Insert(name_four);
	hash.Insert(name_five);
	hash.Insert(name_six);
	hash.Insert(name_seven);
	hash.Insert(name_eight);
	hash.Display();
	std::cout << std::endl;
	std::cout << "Delete two elems:Detry Yun" << std::endl;
	hash.Delete(name_six);
	hash.Delete(name_four);
	hash.Display();
	return 0;

}

 

 

我们定义装填因子(\lambda)为哈希表中元素个数与哈希表的大小 。\lambda 越接近1说明哈希越好。分离链接法使得 \lambda 接近1。

但是分离链接法是通过数组和链表进行组合实现的,也就是使用了大量的链表指针和分配了大量的节点,进而导致效率较慢。有没有更好的算法呢? 当然有呢! 开放定址法可以解决此问题!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值