简单介绍哈希表作用及程序举例

转自: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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值