C++之简单哈希表查找法的实现和循环查找法的比较

散列表 (Hash table,也叫哈希表),是根据关键字(Key value)而直接访问在内存存储位置的数据结构。 也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。 这个映射函数称做散列函数,存放记录的数组称做散列表

哈希表、二叉树、链表是最常见的数据结构,涵盖了程序员面试和笔试中几乎所有的数据结构相关问题。 本文中用C++来实现一个简单的哈希表,帮助理解哈希表是怎样运作的。为了简化代码并突出逻辑,采用简单的除余数作为 散列函数 ,用线性探测来 处理碰撞 。

#include <iostream>
#include <string>
#include <Windows.h>
using namespace std;

class HashItem{
	int key, val;
public:
	HashItem(int k, int v) : key(k), val(v){ };
	const int& getKey(){
		return key;
	}
	const int& getVal(){
		return val;
	}
};

#define LEN 25000*2
//#define LEN 8192

class HashTable{
public:
	static const int SIZE = LEN+2;//需要SIZE足够大,否则死循环
private:
	HashItem ** table;	  // 注意这是二级指针,指向对个HashItem*
public:
	HashTable(){
		table = new HashItem*[SIZE]();	 // 这里的括号是为了初始化为0
	}
	void set(int key, int val){
		int idx = key%SIZE;
		while (table[idx] && table[idx]->getKey() != key)
			idx = (idx + 1) % SIZE;		   // 当SIZE不够大时,这里会陷入死循环。可以检测一下。
		if (table[idx]) delete table[idx];
		table[idx] = new HashItem(key, val);
	}
	//采用简单的除余数作为散列函数,用线性探测来 处理碰撞。
	const int get(int key){
		int idx = key%SIZE;
		while (table[idx] && table[idx]->getKey() != key)
			idx = (idx + 1) % SIZE;           // SIZE不够大时,这里也面临死循环的问题
		return table[idx] ? table[idx]->getVal() : -1;      // 注意这里需要判断key不存在的情况
	}
	~HashTable(){
		for (int i = 0; i<SIZE; i++)
		if (table[i]) 
			delete table[i];
		delete[] table;					 // 别忘了table本身也是要销毁的
	}
};

void test_hash()
{
	cout << "test_hash start" << endl;
	HashTable hash;
	//set data
	for (int i = 0; i < LEN; i++)
	{
		int fd = i + LEN;//保存fd到全局数组中,作为需要查询的数据
		hash.set(fd, i);//fd作为key,索引值i作为值。
	}
	DWORD   dwBeginTime = GetTickCount();//返回开机以来,经历的毫秒数

	for (int i = 0; i < LEN; i++)
	{	//分别去查询数组中i=key对应的值。
		int fd = i+LEN+5;
		int val = hash.get(fd);//使用fd去查询,不存在返回-1,存在则返回他的索引值
		//cout << "key=" << fd << ",val=" << val<<" ";
	}
	cout << endl;
	WORD   dwEndTime = GetTickCount();
	WORD cha = (dwEndTime - dwBeginTime);
	cout << "test_hash end and take time=" << cha << endl << endl;
}
int search_by_loop(int data[], int key)
{
	int j = 0;
	for (j = 0; j < LEN; j++)
	{
		if (data[j] == key)
		{
			break;
		}
	}
	if (j >= LEN)
		j = -1;
	return j;
}
void test_loop()
{
	cout << "test_loop start" << endl;
	int data[LEN] = {0};
	//set data
	for (int i = 0; i < LEN; i++)
	{
		int fd = i + LEN;
		data[i] = fd;//把我的数据fd保存在数组中。
	}

	DWORD   dwBeginTime = GetTickCount();//返回开机以来,经历的毫秒数
	for (int i = 0; i < LEN; i++)
	{
		//分别查询我的数据
		int fd = i+LEN+5;
		int val=search_by_loop(data, fd);
		//cout << "key=" << fd << ",val=" << val << " ";
	}
	cout << endl;
	WORD   dwEndTime = GetTickCount();
	WORD cha = (dwEndTime - dwBeginTime);
	cout << "test_loop end and take time=" << cha << endl << endl;;
}
//http://www.tuicool.com/articles/uiQRre
//C++之简单哈希表查找法的实现和循环查找法的比较(用空间换取时间,提高程序查询的速率,不用循环去查找了)
//实际需求都是根据数据去查找的,而不是根据索引值
void main()
{
	
	test_hash();
	test_loop();
	cout << "ok" << endl;
	cout << "结果是哈希表查找法比循环查找法快很多,特别是数据量大的时候!代价是哈希表空间足够大" << endl;
	int  n;
	cin >> n;
}

#include <iostream>
#include <string>
#include <Windows.h>
using namespace std;

class HashItem{
	int key, val;
public:
	HashItem(int k, int v) : key(k), val(v){ };
	const int& getKey(){
		return key;
	}
	const int& getVal(){
		return val;
	}
};

#define LEN 25000*2
//#define LEN 8192

class HashTable{
public:
	static const int SIZE = LEN+2;//需要SIZE足够大,否则死循环
private:
	HashItem ** table;	  // 注意这是二级指针,指向对个HashItem*
public:
	HashTable(){
		table = new HashItem*[SIZE]();	 // 这里的括号是为了初始化为0
	}
	void set(int key, int val){
		int idx = key%SIZE;
		while (table[idx] && table[idx]->getKey() != key)
			idx = (idx + 1) % SIZE;		   // 当SIZE不够大时,这里会陷入死循环。可以检测一下。
		if (table[idx]) delete table[idx];
		table[idx] = new HashItem(key, val);
	}
	//采用简单的除余数作为散列函数,用线性探测来 处理碰撞。
	const int get(int key){
		int idx = key%SIZE;
		while (table[idx] && table[idx]->getKey() != key)
			idx = (idx + 1) % SIZE;           // SIZE不够大时,这里也面临死循环的问题
		return table[idx] ? table[idx]->getVal() : -1;      // 注意这里需要判断key不存在的情况
	}
	~HashTable(){
		for (int i = 0; i<SIZE; i++)
		if (table[i]) 
			delete table[i];
		delete[] table;					 // 别忘了table本身也是要销毁的
	}
};
int hash_openSize = -1;
int loop_openSize = -1;

void test_hash()
{
	cout << "test_hash start" << endl;
	HashTable hash;
	//set data
	for (int i = 0; i < LEN; i++)
	{
		int fd = i + LEN;//保存fd到全局数组中,作为需要查询的数据
		hash_openSize++;
		hash.set(fd, hash_openSize);//fd作为key,索引值i作为值。
	}
	DWORD   dwBeginTime = GetTickCount();//返回开机以来,经历的毫秒数

	for (int i = 0; i < LEN; i++)
	{	//分别去查询数组中i=key对应的值。
		int fd = i+LEN+5;
		int val = hash.get(fd);//使用fd去查询,不存在返回-1,存在则返回他的索引值
		//cout << "key=" << fd << ",val=" << val<<" ";
	}
	cout << endl;

	int newfd = 1024;
	int index = hash.get(newfd);
	//cout << "index=" << index << endl;
	if (index == -1)//不在哈希表中则插入新的数据
	{
		hash_openSize++;
		hash.set(newfd, hash_openSize);
		cout << "hash end set  newfd=" << newfd << endl;
	}
	WORD   dwEndTime = GetTickCount();
	WORD cha = (dwEndTime - dwBeginTime);
	cout << "test_hash end and take time=" << cha << endl << endl;
}
int search_by_loop(int data[], int key)
{
	int j = 0;
	for (j = 0; j < loop_openSize; j++)
	{
		if (data[j] == key)
		{
			break;
		}
	}
	if (j >= LEN)
		j = -1;
	return j;
}
void test_loop()
{
	cout << "test_loop start" << endl;
	int data[LEN] = {0};
	//set data
	for (int i = 0; i < LEN; i++)
	{
		int fd = i + LEN;
		loop_openSize++;
		data[loop_openSize] = fd;//把我的数据fd保存在数组中。
	}

	DWORD   dwBeginTime = GetTickCount();//返回开机以来,经历的毫秒数
	for (int i = 0; i < LEN; i++)
	{
		//分别查询我的数据
		int fd = i+LEN+5;
		int val=search_by_loop(data, fd);
		//cout << "key=" << fd << ",val=" << val << " ";
	}
	cout << endl;
	WORD   dwEndTime = GetTickCount();
	WORD cha = (dwEndTime - dwBeginTime);
	cout << "test_loop end and take time=" << cha << endl << endl;;
}
//http://www.tuicool.com/articles/uiQRre
//C++之简单哈希表查找法的实现和循环查找法的比较(用空间换取时间,提高程序查询的速率,不用循环去查找了)
//实际需求都是根据数据去查找的,而不是根据索引值
void main()
{
	
	test_hash();
	test_loop();
	cout << "ok" << endl;
	cout << "结果是哈希表查找法比循环查找法快很多,特别是数据量大的时候!代价是哈希表空间足够大" << endl;
	int  n;
	cin >> n;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值