您的位置:首页 > 其它

哈希表KV形式的二次探测

2016-05-31 07:03 169 查看

一、key_value形式的哈希表

哈希表主要有两种形式:

(1)key形式的,存入key的值,然后再去查找key的值

(2)key_value形式的,存入key和对应的value的值,然后通过key来查找value的值,主要可以来实现KV字典查找

对于以上两点本博客并不都一一实现,而是仅仅实现KV形式的

二、K形式和KV形式的相互转换

其实库中也有哈希表这两种的实现,其实K的形式可以转换为KV的形式,也就是V设置成自己的K的形式

如图所示:



三、定义状态数组、仿函数和KV数组

1、定义状态数组

由于哈希表中每个位置的传值不知道设置为什么具体的值好并且删除后不知道设置成什么具体的值好(设置为-1万一保存的就是-1呢),所以设置一个状态数组用来,表示每一个为值上的值的状态,初始时设置为EMPTY,当前位置上存在数字设置为EXIST,要删除当前位置上的值设置为DELETE(也为懒删除法)

enum Status
{
EXIST,
DELETE,
EMPTY,
};

2.定义仿函数

定义放函数的作用主要还是提高代码的复用性,对于不同类型的数据,其处理的函数是不同的,而其他地方的代码都是相似的,这样就可以定义一个仿函数专门来处理哈希函数不同的问题

//仿函数
template<class K>
struct DefaulstHashFuncer
{
size_t operator()(const K& key)
{
return key;
}
};

template<>
struct DefaulstHashFuncer <string>//特化string类型的仿函数
{

static size_t BKDRHash(const char * str)//<span style="color:#ff0000;">字符串的哈希算法</span>
{
unsigned int seed = 131; // 31 131 1313 13131 131313
unsigned int hash = 0;
while (*str)
{
hash = hash * seed + (*str++);
}
return (hash & 0x7FFFFFFF);
}

size_t operator()(const string& str)
{
return BKDRHash(str.c_str());
}
};

3、定义KV数组

template<class K, class V>
struct KeyValue
{
public:
K _key;
V _value;
public:
KeyValue(const K& key = K(), const V& value = V())
:_key(key)
, _value(value)
{}

};


四、具体实现

1、函数声明

template<class K, class V, class HashFuncer = DefaulstHashFuncer<K>>
class HashTaable
{
typedef KeyValue<K, V> KV;
public:
HashTaable();
HashTaable(size_t size);
~HashTaable();

protected:
bool Insert(const K& key, const V& value);
bool Find(const K& key);
bool Remove(const K& key);
void PrintTable();
void Swap(HashTaable<K, V>& ht);

protected:
size_t _HashFuncO(const K& key);
size_t _HashFunc(size_t prevHash, int i);//哈希函数
int _Find(const K& key);
void _CheckCapacity();

protected:
KV* _tables;
size_t _size;
Status* _status;//状态数组
size_t _capacity;
};

2、具体的实现

(1)默认构造函数

HashTaable()
:_tables(NULL)
, _status(NULL)
, _size(0)
, _capacity(0)
{}

(2)构造函数(开辟size大小的空间)

HashTaable(size_t size)
:_tables(new KV[size])
, _status(new Status[size])
, _size(0)
, _capacity(size)
{
//for (_status, EMPTY, sizeof(_status)*_size);//枚举类型不能用memsete因为memset是按字节处理
for (size_t i = 0; i < _capacity; ++i)//若用memset则里面为随机值
{
_status[i] = EMPTY;
}
}


(3)析构函数

~HashTaable()
{
if (_tables)
{
delete[] _tables;
delete[] _status;
_tables = NULL;
_status = NULL;
}
}

(4)插入数据

bool Insert(const K& key,const V& value)
{
/*if (_size == _capacity)
{
cout << "Full" << endl;
return false;
}*/

_CheckCapacity();

int i = 1;
size_t index = _HashFuncO(key);
//二次探测
while (_status[index] == EXIST)
{
if (_tables[index]._key == key)
{
return false;
}
index = _HashFunc(index, i++);
}
_status[index] = EXIST;
_tables[index]._key = key;
_tables[index]._value = value;
++_size;
return true;
}



(5)寻找一个数据

bool Find(const K& key)
{
if (_Find(key) == -1)
{
return false;
}
return true;
}

(6)移除某个数据

bool Remove(const K& key)
{
int index = _Find(key);
if (index!=-1)
{
_status[index] = DELETE;
return true;
}
return false;
}

(7)打印哈希表

void PrintTable()
{
for (size_t i = 0; i < _capacity; ++i)
{
if (_status[i] == EXIST)
{
printf("[%d];E->", i);
cout << _tables[i]._key << endl;
}
else if (_status[i]==DELETE)
{
printf("[%d];D->", i);
cout << _tables[i]._key;
}
else
{
printf("[%d];N", i);
cout << endl;
}
}
}

(8)交换数据

void Swap(HashTaable<K,V>& ht)
{
std::swap(_tables, ht. _tables);
std::swap(_size, ht._size);
std::swap(_status, ht._status);
std::swap(_capacity, ht._capacity);
}


定义的protected函数:

(9)哈希函数初始的位置

size_t _HashFuncO(const K& key)
{
HashFuncer hf;
return hf(key) % _capacity;
}

(10)二次探测哈希函数

size_t _HashFunc(size_t prevHash,int i)//哈希函数
{
return (prevHash + 2 * i - 1) % _capacity;
}
(11)寻找数据(返回下标的位置)
int _Find(const K& key)
{
size_t index = _HashFunc(key);//默认哈希表中一定是有空余的位置的
while (_status[index] != EMPTY)
{
if (_tables[index] == key&&_status[index] != DELETE)
{
return index;
}
++index;
if (index == _capacity)
{
index = 0;
}
}
return -1;
}

(11)增容

void _CheckCapacity()
{
if (_size * 10 >= _capacity * 7)
{
HashTaable<K,V> tmp(2 * _capacity);
for (size_t i = 0; i < _capacity; ++i)
{
if (_status[i] == EXIST)//状态为删除时不用管
{
tmp.Insert(_tables[i]._key,_tables[i]._value);
}
}
this->Swap(tmp);//冲突改变,相对位置改变
}
}

五、测试用例

void Test()
{
//key/value  二次探测  == 》字典
HashTaable<string, string> ht1(13);
ht1.Insert("peter", "张老师");
ht1.Insert("jack", "杰克");
ht1.Insert("rose", "玫瑰");
ht1.PrintTable();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  哈希表