C++之简单哈希表查找法的实现和循环查找法的比较
2017-05-16 16:33
609 查看
散列表 (Hash
table,也叫哈希表),是根据关键字(Key value)而直接访问在内存存储位置的数据结构。 也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。 这个映射函数称做散列函数,存放记录的数组称做散列表
哈希表、二叉树、链表是最常见的数据结构,涵盖了程序员面试和笔试中几乎所有的数据结构相关问题。 本文中用C++来实现一个简单的哈希表,帮助理解哈希表是怎样运作的。为了简化代码并突出逻辑,采用简单的除余数作为 散列函数 ,用线性探测来 处理碰撞 。
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; }
相关文章推荐
- 初学者看过来:简单谈谈 C/C++ 递归的思想,实现,以及和循环的关系
- c++ 栈,队列,循环队列 简单实现
- (C++版)链表(四)——实现双向循环链表创建、插入、删除等简单操作
- 简单循环队列(C++模版技术实现)
- 支持泛型AVL Tree的简单实现,并和STL map比较了插入,删除,查找的性能
- 二叉排序树的建立、插入、删除、查找、比较、4种遍历方式的C++完整实现版
- C++ — 智能指针的简单实现以及循环引用问题
- 循环识别的C++/Java/Go/Scala实现比较
- 用C++实现一个哈希表(插入,删除,查找)
- 简单数据结构之循环链表(C++实现)
- C++ — 智能指针的简单实现以及循环引用问题
- C++中简单实现foreach循环
- 【C++基本功补习】查找三个数据中的最大值、最小值、中间值,两种实现方案比较
- 简单谈谈 C/C++ 递归的思想,实现,以及和循环的关系
- C/C++程序——递归和循环实现阶乘,并比较N!与(2N N)的大小
- C++ 智能指针——简单实现以及循环引用问题
- C++ 双循环链表简单实现
- 支持泛型AVL Tree的简单实现,并和STL map比较了插入,删除,查找的性能
- C++ 哈希表 (hashtable) 用于保存简单的数据,及数据查找,数据删除
- 循环识别的C++/Java/Go/Scala实现比较