您的位置:首页 > 理论基础 > 数据结构算法

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

2016-05-30 17:19 519 查看
构造哈希表常用的方法是:
除留余数法--取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。HashKey= Key % P。
直接定址法--取关键字的某个线性函数为散列地址HashKey= Key 或 HashKey= A*Key + BA、B为常数。

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

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

哈希冲突是什么呢?哈希冲突指的是:不同的关键字经过相同的哈希函数映射到相同的的哈希地址处。
要解决哈希冲突闭散列方法主要有两个:线性探测与二次探测。

在这里,我将线性探测的原理用下图表述:
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M00/7F/ED/wKioL1cx8DLSdmtAAAA-6R6ERMM545.png" title="EUDE)47J0H$NZ{NBYP2){WF.png" alt="wKioL1cx8DLSdmtAAAA-6R6ERMM545.png" />线性探测
650) this.width=650;" src="http://s1.51cto.com/wyfs02/M00/7F/F0/wKiom1cx7xSj2RBeAAA-6R6ERMM128.png" title="EUDE)47J0H$NZ{NBYP2){WF.png" alt="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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐