链地址法实现的哈希表结构(一)
- 该链表中存放的是键值对
#include<iostream>
#include<vector>
#include<list>
using namespace std;
template<typename T>
class CHash
{
public:
int operator()(const T &val)
{
return val;//默认用除留余数法
}
}; // string User People
template<>
class CHash<string>//特例化
{
public:
int operator()(const string &val)
{
int sum = 0;
for (int i = 0; i < val.length(); ++i)
{
sum += (val[i] >> i);
}
return sum;
}
};
// key 链地址法实现的哈希表结构 【key,id value Person】
template<typename K, typename V>
struct MyPair
{
MyPair(K k = K(), V v = V())
:first(k), second(v) {}
K first; // key
V second; // value
};
template<typename K, typename V>
bool operator==(const MyPair<K, V> &lhs, const MyPair<K, V> &rhs)
{
return lhs.first == rhs.first;
}
template<typename K, typename V>
MyPair<K, V> mymake_pair(const K &key, const V &val)
{
return MyPair<K, V>(key, val);
}
template<typename K, typename V, typename HashType = CHash<K>>
class CHashMap // 映射表 key -> value
{
public:
CHashMap(int size = 3, double lf = 0.75)
:_loadFactor(lf), _usedBuckets(0)
{
// 给哈希表开辟数组空间的
_hashVec.resize(size);
}
void put(const MyPair<K, V> &pair)
{
double lf = _usedBuckets * 1.0 / _hashVec.size();
cout << "size:" << _hashVec.size() << " loadfactor:" << lf << endl;
if (lf >= _loadFactor)
{
resize();
}
int index = _hash(pair.first) % _hashVec.size();
list<MyPair<K,V>> &curList = _hashVec[index];
if (curList.empty())
{
curList.push_front(pair);
_usedBuckets++;
}
else
{
auto it = find(curList.begin(), curList.end(), pair);
if (it == curList.end())
{
curList.push_front(pair);
}
}
}
// 删除哈希表中的元素
void remove(const K &key)
{
int index = _hash(key) % _hashVec.size();
list<MyPair<K, V>> &curList = _hashVec[index];
if (!curList.empty())
{
// 1.在list怎么找val
auto it = find(curList.begin(), curList.end(), MyPair<K,V>(key));
// 2.找到val,删除,找不到,return
if (it != curList.end())
{
curList.erase(it);
// 3.删除val,如果桶变成空的,要给
if (curList.empty())
{
_usedBuckets--;
}
}
}
}
// 在哈希表中查找元素 table.query(10); table[10]
// map["3452346"] 1.查询功能 2.赋值功能 map["3452346"]="zhangsan" 3.增加
V& operator[](const K &key) // MyPair<K,V>
{
int index = _hash(key) % _hashVec.size();
list<MyPair<K, V>> &curList = _hashVec[index];
if (!curList.empty())
{
// 1.在list怎么找val
auto it = find(curList.begin(), curList.end(), MyPair<K, V>(key));
// 2.找到val,删除,找不到,return
if (it != curList.end())
{
return it->second;
}
}
// 没有找到
curList.push_front(MyPair<K,V>(key));
//return curList.insert(curList.begin(), MyPair<K, V>(key))->second;
return curList.begin()->second;
}
private:
vector<list<MyPair<K, V>>> _hashVec;
double _loadFactor; // 记录加载因子
int _usedBuckets;
HashType _hash; // 专门计算T类型对象的哈希值的
//获取素数
int getPrime(int n)
{
for (int i = n + 1;; ++i)
{
int k = sqrt(i);
int j = 2;
for (; j <= k; ++j)
{
if (i % j == 0)
break;
}
if (j > k)
{
return i;
}
else
{
continue;
}
}
}
// 动态扩容
void resize()
{
// 1.先把现有的哈希表交换到老的容器当中
vector<list<MyPair<K, V>>> _oldhash;
_oldhash.swap(_hashVec);
// 2.给_hashVec resize桶内存
_hashVec.resize(getPrime(_oldhash.size()));
// 3.遍历old哈希表,的每一个链表的节点,计算其散列码,splice到新的hash中
for (auto it = _oldhash.begin(); // it -> list<int>
it != _oldhash.end();
++it)
{
if (!it->empty())
{
for (auto it1 = it->begin(); it1 != it->end();)
{
int index = _hash(it1->first) % _hashVec.size();
list<MyPair<K, V>> &mylist = _hashVec[index];
if (!mylist.empty())
{
// 4.如果桶被第一次占用,_usedBuckets++
_usedBuckets++;
}
// 把旧的hash表中的list节点直接搬到新的哈希表当中
mylist.splice(mylist.begin(), *it, it1);
it1 = it->begin();
}
}
}
}
};
int main()
{
CHashMap<int, int> hashMap;
hashMap.put(mymake_pair(10, 20));
hashMap.put(mymake_pair(14, 45));
hashMap.put(mymake_pair(18, 73));
hashMap.put(mymake_pair(19, 89));
hashMap[20] = 987;
cout << hashMap[20] << endl;
return 0;
}
list成员splice函数的用法
语法
void splice( iterator pos, list &lst; );
void splice( iterator pos, list &lst;, iterator del );
void splice( iterator pos, list &lst;, iterator start, iterator end );
解释
- splice()函数把lst连接到pos的位置。如果指定其他参数,则插入lst中del所指元素到现链表的pos上,或者用start和end指定范围。
链地址法实现的哈希表结构(二)
- 该哈希表中只存放单个数据
template<typename T>
class CHash
{
public:
int operator()(const T &val)
{
// 默认用除留余数法
return val;
}
};
template<>
class CHash<string>
{
public:
int operator()(const string &val)
{
// hello olleh
int sum = 0;
for (int i = 0; i < val.length(); ++i)
{
sum += (val[i]>>i);
}
return sum;
}
};
// 链地址法实现的哈希表结构
template<typename T, typename HashType = CHash<T>>
class CHashTable
{
public:
CHashTable(int size = 3, double lf = 0.75)
:_loadFactor(lf), _usedBuckets(0)
{
// 给哈希表开辟数组空间的
_hashVec.resize(size);
}
void put(const T &val)
{
double lf = _usedBuckets * 1.0 / _hashVec.size();
cout << "size:" << _hashVec.size() << " loadfactor:" << lf << endl;
if (lf >= _loadFactor)//动态扩容的条件
{
resize();
}
int index = _hash(val) % _hashVec.size();
list<int> &curList = _hashVec[index];
if (curList.empty())
{
curList.push_front(val);
_usedBuckets++;
}
else
{
auto it = find(curList.begin(), curList.end(), val);
if (it == curList.end())
{
curList.push_front(val);
}
}
}
// 删除哈希表中的元素
void remove(const T &val)
{
int index = _hash(val) % _hashVec.size();
list<T> &curList = _hashVec[index];
if (!curList.empty())
{
// 1.在list怎么找val
auto it = find(curList.begin(), curList.end(), val);
// 2.找到val,删除,找不到,return
if (it != curList.end())
{
curList.erase(it);
// 3.删除val,如果桶变成空的,要给
if (curList.empty())
{
_usedBuckets--;
}
}
}
}
// 在哈希表中查找元素 table.query(10); table[10]
bool operator[](const T &val)
{
int index = _hash(val) % _hashVec.size();
list<T> &curList = _hashVec[index];
if (!curList.empty())
{
// 1.在list怎么找val
auto it = find(curList.begin(), curList.end(), val);
// 2.找到val,删除,找不到,return
if (it != curList.end())
{
return true;
}
}
return false;
}
private:
vector<list<int>> _hashVec;
double _loadFactor; // 记录加载因子
int _usedBuckets;
HashType _hash; // 专门计算T类型对象的哈希值的
//获取素数
int getPrime(int n)
{
for (int i = n + 1;; ++i)
{
int k = sqrt(i);
int j = 2;
for (; j <= k; ++j)
{
if (i % j == 0)
break;
}
if (j > k)
{
return i;
}
else
{
continue;
}
}
}
// 动态扩容
void resize()
{
// 1.先把现有的哈希表交换到老的容器当中
vector<list<int>> _oldhash;
_oldhash.swap(_hashVec);
// 2.给_hashVec resize桶内存
_hashVec.resize(getPrime(_oldhash.size()));
// 3.遍历old哈希表,的每一个链表的节点,计算其散列码,splice到新的hash中
for (auto it = _oldhash.begin(); // it -> list<int>
it != _oldhash.end();
++it)
{
if (!it->empty())
{
for (auto it1 = it->begin(); it1 != it->end();)
{
int index = _hash(*it1) % _hashVec.size();
list<int> &mylist = _hashVec[index];
if (!mylist.empty())
{
// 4.如果桶被第一次占用,_usedBuckets++
_usedBuckets++;
}
// 把旧的hash表中的list节点直接搬到新的哈希表当中
mylist.splice(mylist.begin(), *it, it1);
it1 = it->begin();
}
}
}
}
};
int main()
{
CHashTable<int> hash;
srand(time(NULL));
for (int i = 0; i < 8; i++)
{
hash.put(i);
}
return 0;
}
线性探测法实现的哈希结构
template<typename T, typename HashType= CHash<T>>
class CHashTable
{
public:
CHashTable(int size = 3, double lf = 0.75)
:_loadFactor(lf), _usedBuckets(0)
{
// 给哈希表开辟数组空间的
_hashVec.resize(size);
}
void put(const T &val)
{
double lf = _usedBuckets * 1.0 / _hashVec.size();
cout << "size:"<< _hashVec.size() << " loadfactor:" << lf << endl;
if (lf >= _loadFactor)
{
resize();
}
int index = _hash(val) % _hashVec.size();
for (int i = index;;i = (i + 1) % _hashVec.size())
{
// STATE_UNUSE STATE_USE STATE_USED
if (_hashVec[i]._state != STATE_USE)
{
_hashVec[i]._data = val;
_hashVec[i]._state = STATE_USE;
_usedBuckets++;
break;
}
}
}
// 删除哈希表中的元素
void remove(const T &val)
{
int index = _hash(val) % _hashVec.size();
int flag = (index - 1 + _hashVec.size()) % _hashVec.size();
for (int i = index; ;i = (i + 1) % _hashVec.size())
{
if (_hashVec[i]._state == STATE_UNUSE)
return;
if (_hashVec[i]._state == STATE_USE
&&_hashVec[i]._data == val)
{
_hashVec[i]._state = STATE_USED;
_usedBuckets--;
break;
}
if (i == flag)
{
return;
}
}
}
// 在哈希表中查找元素
bool query(const T &val)
{
int index = _hash(val) % _hashVec.size();
int flag = (index - 1 + _hashVec.size()) % _hashVec.size();
for (int i = index; ;i = (i + 1) % _hashVec.size())
{
if (_hashVec[i]._state == STATE_UNUSE)
return;
if (_hashVec[i]._state == STATE_USE
&& _hashVec[i]._data == val)
{
return true;
}
if (i == flag)
{
return false;
}
}
}
private:
// STATE_UNUSE 删除 STATE_USED 0
enum STATE{ STATE_UNUSE, STATE_USE, STATE_USED };
struct Node
{
Node(T data = T())
:_data(data), _state(STATE_UNUSE)
{}
T _data;
STATE _state;
};
vector<Node> _hashVec;
double _loadFactor; // 记录加载因子
int _usedBuckets;
HashType _hash; // 专门计算T类型对象的哈希值的
//static int _prime[] = {3,11,29, }; 枚举素数
//获取素数
int getPrime(int n)
{
for (int i = n + 1;; ++i)
{
int k = sqrt(i);
int j = 2;
for (; j <= k; ++j)
{
if (i % j == 0)
break;
}
if (j > k)
{
return i;
}
else
{
continue;
}
}
}
// 动态扩容
void resize()
{
vector<Node> _oldhash;
_oldhash.swap(_hashVec);
_usedBuckets = 0;
int prime = getPrime(_oldhash.size());
_hashVec.resize(prime);
//vector<Node> _newhash;
//_newhash.resize(get_prime(_hashVec.size()));
for (int i = 0; i < _oldhash.size(); ++i)
{
// STATE_UNUSE STATE_USE STATE_USED
if (_oldhash[i]._state == STATE_USE)
{
put(_oldhash[i]._data);
}
}
}
};
int main()
{
CHashTable<int> hash;
srand(time(NULL));
for (int i = 0; i < 8; i++)
{
//hash.put(rand() % 100 + 1);
hash.put(i);
}
hash.put(2);
hash.display();
hash.remove(2);
hash.display();
hash.put(2);
hash.display();
cout << hash.query(3) << endl;
cout << hash.query(2) << endl;
return 0;
}