hashtable模板的简单实现(二)
转载注明出处
知识标签:hashtable tamplate C++ 函数指针
本程序使用
线性探测法
数学递推公式
Hi = ( H(key) + di ) % m
- Hi表示发生冲突时第i次探测的散列地址
- H(key)表示根据key值第一次获得的散列地址
- di为增量序列,本程序取di = 1, 3, 5, 7…
- m为散列表长
code
hashtable.h
#ifndef __HASHTABLE_H__
#define __HASHTABLE_H__
#include<iostream>
#include<vector>
#include<functional>
template<typename T>
class hashtable
{
public:
typedef size_t (*HS)(const T&);
//构造函数,初始化函数指针变量,hash数组大小,hashtable当前元素个数
hashtable(HS hs, size_t size = 100) : phash(hs), array(size), currentSize(0)
{//array(size)调用hashElem的无参构造函数size次,而每个hashElem无参构造函数调用T的无参构造函数1次
//为每个hashElem进行逻辑初始化
for(size_t i = 0; i != array.size(); ++i)
array[i].flag = EMPTY;
}
~hashtable(){}
//判断t是否在hashtable中
bool isin(const T& t)
{
return array[getindex(t)].flag == ACTIVE;
}
//逻辑删除t
bool remove(const T& t)
{
hashElem& he = array[getindex(t)];
if(he.flag != ACTIVE)
return false;
else
{
he.flag = DELETED;
--currentSize;
return true;
}
}
//插入t
bool insert(const T& t)
{
hashElem& he = array[getindex(t)];
//如果存在该元素,且该元素有效,插入失败
if(he.flag == ACTIVE)
return false;
if(he.flag == DELETED)
{//如果存在该元素,且该元素无效。把它置为有效,表示逻辑添加
he.flag = ACTIVE;
}
else
{//如果不存在该元素
//1.调用hashElem的operator= 2.调用两参构造函数
he = hashElem(t, ACTIVE);
//保证负载因子 <= 0.5
if(currentSize + 1 > array.size() / 2)
resize2();
}
++currentSize;
return true;
}
void show()
{
typename std::vector<hashElem>::iterator iter = array.begin();
while(iter != array.end())
{
//下句代码可得:T一定要重载operator<<
if((*iter).flag == ACTIVE)
std::cout << (*iter).element << std::endl;
else
std::cout << "---" << std::endl;
++iter;
}
}
//array元素内存空间的三种状态标记
enum elemFlag {EMPTY, ACTIVE, DELETED};
class hashElem
{
public:
T element;
elemFlag flag;
hashElem(){}
//调用T的拷贝构造函数
hashElem(const T& em, elemFlag ef) : element(em), flag(ef){}
};
public:
//hash函数指针
HS phash;
//hashtable数组
std::vector<hashElem> array;
//hashtable当前大小
size_t currentSize;
private:
//返回值currentIndex的2种情况:1.存储过值,且等于x 2.没存储过值
size_t getindex(const T& t)
{//如果array[currentPos]中存储过值,但不等于t,就继续向下寻找
size_t currentIndex = myhash(t);
size_t offset = 1;
//T一定要重载operator!=
while(array[currentIndex].flag != EMPTY && array[currentIndex].element != t)
{//如果array[currentPos]中存储过值,但不等于x,就继续向下寻找
//Hi = ( H(T) + offseti ) % array.size()
//其中offseti = 1, 3, 5, 7...
currentIndex += offset;
if(currentIndex >= array.size())
{
currentIndex %= array.size();
}
offset += 2;
}
return currentIndex;
}
//hashtable以2倍大小自增长
void resize2()
{
//备份
std::vector<hashElem> oldarray = array;
//扩容
array.resize(2 * array.size());
for(size_t i = 0; i != array.size(); ++i)
array[i].flag = EMPTY;
currentSize = 0;
//转移数据到新hashtable
for(size_t i = 0; i != oldarray.size(); ++i)
if(oldarray[i].flag == ACTIVE)
insert(oldarray[i].element);
}
size_t myhash(const T& t)
{//压缩映射
return phash(t) % array.size();
}
};
#endif
main.cpp
#include<iostream>
#include<string>
#include<functional>
#include "hashtable.h"
class node
{
public:
std::string name;
size_t score;
public:
node(){}
node(const std::string& str, size_t sc)
{
name = str;
score = sc;
}
node(const node& nd)
{
name = nd.name;
score = nd.score;
}
friend bool operator!=(const node& left, const node& right)
{
return left.name != right.name;
}
//operator=可省略,因为系统自动生成
node& operator=(const node& other)
{
name = other.name;
score = other.score;
return *this;
}
friend std::ostream& operator<<(std::ostream& out, node& nd)
{
out << "( " << nd.name << ", " << nd.score << " )" << std::flush;
return out;
}
};
size_t myhash(const node& nd)
{
return std::hash<std::string>()(nd.name);
}
int main(void)
{
hashtable<node> ht(&myhash, 6);
ht.insert(node("小明", 45));
ht.insert(node("小花", 89));
ht.insert(node("小红", 88));
ht.insert(node("小王", 78));
ht.insert(node("小黄", 99));
ht.insert(node("小李", 76));
ht.insert(node("小周", 65));
ht.insert(node("小马", 98));
ht.show();
std::cout << "---------------------------" << std::endl;
ht.remove(node("小马", 98));
ht.remove(node("小红", 88));
ht.show();
if(ht.isin(node("小马", 98)))
std::cout << "in" << std::endl;
else
std::cout << "not in" << std::endl;
return 0;
}
结果
第二张