转自:http://blog.csdn.net/songzi1111/article/details/10985429
转自:http://blog.csdn.net/yleek/article/details/8691938
举一个不太恰当的例子方便理解:
比如几个数字(1,11,25,47,57)和一个二维数组arr[10][10],
我们用除以10的余数作为这些数字的分类标准,并按照余数存入相应下标的二维数组里。
得到的结果是:
arr[1][0] == 1;arr[1][1] == 11;
arr[5][0] == 25;
arr[7][0] == 47;arr[7][1] == 57;
查找哈希表:
比如查找57,58,首先对他们除以10得到余数,分别是7和8,
57就会在arr[7]中从arr[7][0]进行遍历查找知道最后,当查找到arr[7][1]时找到匹配项,查找结束。
58就会在arr[8]中从arr[8][0],由于arr[8]没有数据,所以哈希表中没有匹配项。
Hash原理:
设要存储对象的个数为num, 那么我们就用len个内存单元来存储它们(len>=num); 以每个对象ki的关键字为自变量,用一个函数h(ki)来映射出ki的内存地址,也就是ki的下标,将ki对象的元素内容全部存入这个地址中就行了。这个就是Hash的基本思路。
现在我要存储4个元素 13 7 14 11
显然,我们可以用数组来存。也就是:a[1] = 13; a[2] = 7; a[3] = 14; a[4] = 11;
当然,我们也可以用Hash来存。下面给出一个简单的Hash存储:
先来确定那个函数。我们就用h(ki) = ki%5;(这个函数不用纠结,我们现在的目的是了解为什么要有这么一个函数)。
对于第一个元素 h(13) = 13%5 = 3; 也就是说13的下标为3;即Hash[3] = 13;
对于第二个元素 h(7) = 7 % 5 = 2; 也就是说7的下标为2; 即Hash[2] = 7;
同理,Hash[4] = 14; Hash[1] = 11;
现在我要你查找11这个元素是否存在。对于数组来说,一个for循环就可以了。
也就是说我们要找4次。
Hash找一下。首先,我们将要找的元素11代入刚才的函数中来映射出它所在的地址单元。也就是h(11) = 11%5 = 1 了。下面我们来比较一下Hash[1]是否等于11, 这个问题就很简单了。也就是说我们就找了1次。
下面是c++实现哈希表的代码 :
//////////////////////////
// 用连地址表示的哈希表
//////////////////////////
#include <iostream>
using namespace std;
template <typename T>
class Node
{
public:
Node(T val = 0) : key(val), next(NULL), val(88)
{
// 为什么这里的赋值通过offset宏看不到,看到的只是初始化列表里的88
val = 33;
}
int val;
Node * next;
T key;
};
template <typename T>
class HashTable
{
public:
// 建立一个哈希表要指定大小和哈希函数
HashTable(int size, int (*hashFunc)(const T &)) : m_size(size), m_hashFunc(hashFunc)
{
m_ht = new Node<T> * [m_size];
for(int i = 0; i < m_size; ++i)
m_ht[i] = NULL;
}
~HashTable()
{
for(int i = 0; i < m_size; ++i)
{
Node<T> *p = m_ht[i];
while(p != NULL)
{
Node<T> * cur = p;
p = p->next;
delete cur;
}
}
delete m_ht;
}
T * Find(const T & x);
void Insert(const T & x);
private:
int m_size;
Node<T> ** m_ht; // hash table
int (*m_hashFunc)(const T &);
};
// 查找
template <typename T>
T * HashTable<T>::Find(const T & x)
{
int pos = m_hashFunc(x);
Node<T> * p = m_ht[pos];
while(p != NULL)
{
if(p->key == x)
return &p->key;
p = p->next;
}
return NULL;
}
// 插入
template <typename T>
void HashTable<T>::Insert(const T & x)
{
int pos = m_hashFunc(x);
Node<T> ** p = &m_ht[pos];
while(*p != NULL)
p = &((*p)->next);
*p = new Node<T>(x);
}
/////////////////////////////////////////////////
// 哈希函数,保正哈希值均匀的落在哈希表的空间内
/////////////////////////////////////////////////
int HashFunc(const int & x)
{
return x % 10;
}
#define MEMOFF(struc, e) (size_t)&(((struc*)0)->e)
int main()
{
HashTable<int> ht(10, HashFunc);
ht.Insert(1);
ht.Insert(2);
ht.Insert(3);
int* res = ht.Find(3);
if (res != NULL)
{
cout << *res << endl;
size_t offset = MEMOFF(Node<int>, key);
Node<int> *s = (Node<int>*)((size_t)res - offset);
cout << s->val << endl;
}
else
cout << "not found" << endl;
return 0;
}