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;
}
結果
第二張