您的位置:首页 > 编程语言 > C语言/C++

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

2017-05-16 16:33 609 查看
散列表 (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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: