【数据结构】哈希表的线性探测算法

原创 2016年05月30日 17:19:04

构造哈希表常用的方法是:

除留余数法--取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。HashKey= Key % P。

直接定址法--取关键字的某个线性函数为散列地址HashKey= Key 或 HashKey= A*Key + BA、B为常数。


我在这里主要使用一下除留余数法Hash(key) =Key%P,(P这里是哈希表的长度)p最好是素数考虑降低哈希冲突的原因,我并没有在这上面过于追究此处哈希表长度10,见线性探测图。


哈希表经常遇到的一个问题就是哈希冲突


哈希冲突是什么呢?哈希冲突指的是:不同的关键字经过相同的哈希函数映射到相同的的哈希地址处。

要解决哈希冲突闭散列方法主要有两个:线性探测与二次探测。


在这里,我将线性探测的原理用下图表述:

wKioL1cx8DLSdmtAAAA-6R6ERMM545.png

线性探测

wKiom1cx7xSj2RBeAAA-6R6ERMM128.png


线性探测代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

#include<string>

//线性探测的特化处理可以处理自定义类型的数据
enum State
{
   EMPTY,//该位置未存放元素
   DELETE,//该位置元素已被删除
   EXIST,//该位置存在元素
};

//处理基本类型
template<class K>
struct DefaultFuncer
{
    size_t operator()(const K& key)
    {
        return key;
    }
};

//处理自定义类型
template<>
struct DefaultFuncer<string>
{
    size_t value = 0;
    size_t operator()(const string& str)
    {
        for (int i = 0; i < str.size(); i++)
        {
            value += str[i];
        }
        return value;
    }    
};


template<class K, template<class>class HashFuncer = DefaultFuncer>
class HashTable
{
public:
    HashTable()
        :_size(0)
        , _capacity(0)
        , _state(NULL)
        , _table(NULL)
    {}

       HashTable(size_t size)
            :_size(0)
            , _capacity(size)
            , _state(new State[size])
            , _table(new K[size])
        {
            for (int i = 0; i < _capacity; i++)//全部状态初始化成EMPTY
            {
                _state[i] = EMPTY;
            }
        }


        //线性探测计算出元素存放位置(假设不哈希冲突)
        int _HashFunc(const K& key)
        {
            HashFuncer<K> hf;
            return hf(key) % _capacity;
    
            //匿名对象调用operator()
            /*return HashFuncer<K>()(key) % _capacity;*/
        }
    
        void Swap(HashTable<K> tmp)
        {
            swap(_size, tmp._size);
            swap(_capacity, tmp._capacity);
            swap(_state, tmp._state);
            swap(_table, tmp._table);
        }
    
    
        void _CheckCapacity()
        {                
            HashTable<K> tmp(2*_capacity);
            for (int i = 0; i < _capacity; i++)
            {
                tmp.Insert(_table[i]);
            }
            Swap(tmp);
        }
        
    
        bool Insert(const K& key)
        {
            //静态哈希表
            /*if (_size == _capacity)
            {
                cout<<"HashTable is full!"<<endl;
                return false;
            }*/
    
            //动态哈希表
            //高效哈希表的载荷因子大概稳定在0.7-0.8较好
            if (10 * _size >= 7 * _capacity)
            {
                _CheckCapacity();
            }
    
            int index = _HashFunc(key);
        
            while (_state[index] == EXIST)
            {        
                index++;
                if (index == _capacity)
                {
                    index = 0;
                }
            }
    
            _table[index] = key;
            _state[index] = EXIST;
            _size++;
            return true;    
        }
    
    
        int Find(const K& key)
        {
            int index = _HashFunc(key);
            while (_state[index] == EXIST || _state[index]== DELETE)
            //while(_state[index] != EMPTY)    //空状态找不到,非空状态找得到
            {
                if (_table[index] == key && _state[index] == EXIST)
                {
                    return index;
                }
                ++index;
                if (index == _capacity)
                {
                    index = 0;
                }
            }
            return -1;    
        }
    
    
        bool Remove(const K& key)
        {
            int index = Find(key);
            if (index != -1)
            {
                _state[index] = DELETE;
                --_size;
                return true;
            }
            return false;
        }
    
    
        void PrintTable()
        {
            for (int i = 0; i < _capacity; i++)
            {
                if (_state[i] == EXIST )
                {
                    cout << i << "(EXIST):" << _table[i] << endl;
                }
                /*我将DELETE状态元素也打印出来,便于观察。
                而Insert处理时,DELETE状态下的位置可以插上新的元素*/
                else if (_state[i] == DELETE)
                {
                    cout << i << "(DELETE):" << _table[i] << endl;
                }
                else
                {
                    cout << i << "(EMPTY):" << _table[i] << endl;
                }
            }
        }

private:
        size_t _size;//实际存放元素个数
        size_t _capacity;//哈希表长度
        State* _state;
        K* _table;
};


//POD(基本类型)的测试用例
void TestHashTablePOD()
{
    HashTable<int> ht(10);
    ht.Insert(89);
    ht.Insert(18);
    ht.Insert(49);
    ht.Insert(58);
    ht.Insert(9);
    ht.PrintTable();

    int ret = ht.Find(89);
    cout << ret << endl; 

    ht.Remove(89);
    ht.PrintTable();

    ht.Remove(18);
    ht.PrintTable();
}


//自定义类型的测试用例
void TestHashTable()
{
    HashTable<string,DefaultFuncer> ht(10);
    ht.Insert("信息化");
    ht.Insert("时代");
    ht.Insert("电脑");
    ht.Insert("测试工程师");
    ht.PrintTable();

    int ret = ht.Find("测试工程师");
    cout << ret << endl;

    ht.Remove("电脑");
    ht.PrintTable();

    ht.Remove("时代");
    ht.PrintTable();
}


int main()
{
    TestHashTable();
    system("pause");
    return 0;
}

本文出自 “Han Jing's Blog” 博客,请务必保留此出处http://10740184.blog.51cto.com/10730184/1771160

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

C++数据结构--.哈希表线性探测开放寻址法与独立表链地址法

1.哈希函数是个定位函数,它用键作为参数,返回表中的索引值   2.线性探测开放寻址法   *调用哈希函数处理键得到哈希值,用值除以表的长度后取余数,从而确定表中的一个位置   *如果该位置非空...

数据结构 c语言实现哈希(hash)表查找 除留余数法构建hash函数开放定值法线性探测处理冲突

一.hash函数头文件实现hash.h #ifndef __HASH_H__ #define __HASH_H__ #include #include #include #include ...

搜索结构之哈希表(线性探测法)

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列...

数据结构与算法之散列(线性/平方/双平方探测法)<八>

散列的基础知识以及分离链式法参考 上一篇 数据结构与算法之散列(分离链接法)线性探测法 若产生冲突则放入下一个空闲区域 但是当数据多 需要发费很多的时间寻找空单元 更糟糕的是,即使表比较...

数据结构实验之查找七:线性之哈希表

数据结构实验之查找七:线性之哈希表Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description根据给定...

linux中C语言函数:数据结构函数(二分查找、二叉树、哈希表、线性搜索)

1. qsort 、bsearch 包含头文件:#include void qsort(void *base , size_t nmemb , size_t size, int(*comopare)(...

Javascript数据结构算法之散列(霍纳算法,开链法,线性探测-寻址法)

使用散列存储数据时,通过一个散列函数将键映射为一个数字,这个数字的范围时0到散列表的长度。理想情况下,散列函数会将每个键值映射为唯一的数组索引。一个更现实的目标是将键均匀分布。 在散列上插入...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)