#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
typedef struct hashtable_node // 節點
{
hashtable_node *next;
size_t value;
}node, *pnode;
enum{stl_num_primes = 28}; // 素數表大小
static const unsigned long stl_prime_list[stl_num_primes] = // 素數表 重建hashtable從此選數建表
{
53, 97, 193, 389, 769,
1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433,
1572869, 3145739, 6291469, 12582917, 25165843,
50331653, 100663319, 201326611, 402653189, 805306457,
1610612741, 3221225473ul, 4294967291ul
};
inline unsigned long stl_next_prime(unsigned long n) // 返回大於n的最小素數
{
const unsigned long *first = stl_prime_list;
const unsigned long *last = stl_prime_list + stl_num_primes;
const unsigned long *pos = lower_bound(first, last, n);
return pos == last ? *(last - 1) : *pos;
}
/*unsigned long* lower_bound(unsigned long* first, const unsigned long* last, const size_t& value) // 二分求大於value的最小數
{
size_t len = last - first;
size_t half = 0;
unsigned long *middle = nullptr;
while (len > 0)
{
half = len >> 1;
middle = first + half;
if (*middle <= value)
{
first = middle + 1;
len = len - half - 1;
}
else
{
len = half;
}
}
return first;
}
*/
class hashtable
{
public :
hashtable(const size_t &n) // 初始化一個hashtable
{
const size_t n_buckets = stl_next_prime(n);
buckets.reserve(n_buckets);
buckets.insert(buckets.end(), n_buckets, nullptr);
num_elements = 0;
}
node *new_node(const size_t &obj) //創建一個節點
{
node *n = new node();
n->next = nullptr;
n->value = obj;
return n;
}
void delete_node(node *n) // 刪除一個節點
{
n->next = nullptr;
n->value = 0;
delete n;
n = nullptr;
}
size_t bkt_num(const size_t &obj, size_t n) const // 計算出在buckets中的位置
{
return obj % n;
}
size_t bucket_count() const // 返回桶數
{
return buckets.size();
}
size_t size() const // 返回節點數
{
return num_elements;
}
size_t bucket_max_count() const // 返回表中最多節點數
{
return stl_prime_list[stl_num_primes-1];
}
size_t elems_in_bucket(size_t bucket) const //返回指定key映射了多少value
{
size_t result = 0;
for (node *cur = buckets[bucket]; cur; cur = cur->next)
{
result += 1;
}
return result;
}
node * find(const size_t &obj) // 返回所找目標的位置
{
const size_t n = bkt_num(obj, buckets.size());
node *first;
for (first = buckets[n]; first && !(first->value == obj); first = first->next){}
return first;
}
void resize(size_t num_elments_hint) // 調整hashtable的容量
{
const size_t old_n = buckets.size();
if (num_elments_hint > old_n)
{
const size_t n = stl_next_prime(num_elments_hint);
if (n > old_n)
{
vector<pnode> tmp(n, nullptr); // 建立新的線性表來擴充容量
for (size_t bucket = 0; bucket < old_n; ++bucket) // 開始copy
{
pnode first = buckets[bucket];
while (first)
{
size_t new_bucket = bkt_num(first->value, n);
buckets[bucket] = first->next;
first->next = tmp[new_bucket]; // copy每個node
tmp[new_bucket] = first;
first = buckets[bucket];
}
}
buckets.swap(tmp); // 交換內部數據結構
}
}
}
void insert_unique_noresize(const size_t &obj) // 找不到重複元素就插入
{
const size_t n = bkt_num(obj, buckets.size());
pnode first = buckets[n];
for (pnode cur = first; cur; cur = cur->next)
{
if (cur->value == obj)
{
return;
}
}
pnode tmp = new_node(obj);
tmp->next = first;
buckets[n] = tmp;
++num_elements;
}
void insert_equal_noresize(const size_t &obj) // 有重複元素也插入
{
const size_t n = bkt_num(obj, buckets.size());
pnode first = buckets[n];
for (pnode cur = first; cur; cur = cur->next)
{
if (cur->value == obj)
{
pnode tmp = new_node(obj);
tmp->next = cur->next;
cur->next = tmp;
++num_elements;
return;
}
}
node* tmp = new_node(obj);
tmp->next = first;
buckets[n] = tmp;
++num_elements;
}
void insert_unique(const size_t &obj) // 不允許有重複元素的插入
{
resize(num_elements+1);
insert_unique_noresize(obj);
}
void insert_equal(const size_t &obj) // 允許有重複元素的插入
{
resize(num_elements+1);
insert_equal_noresize(obj);
}
size_t erase(const size_t &obj) // 刪除元素 包括重複的
{
const size_t n = bkt_num(obj, buckets.size());
pnode first = buckets[n];
size_t erased = 0;
if (first)
{
pnode cur = first;
pnode next = cur->next;
while (next)
{
if (next->value == obj)
{
cur->next = next->next;
delete_node(next);
next = cur->next;
++erased;
--num_elements;
}
else
{
cur = next;
next = next->next;
}
if (first->value == obj)
{
buckets[n] = first->next;
delete_node(first);
++erased;
--num_elements;
}
}
}
return erased;
}
private :
vector<pnode> buckets;
size_t num_elements;
};
int main()
{
hashtable hash(10000);
cout << hash.bucket_count() << endl << hash.bucket_max_count() << endl;
hash.insert_equal(100);
cout << hash.bkt_num(100, hash.bucket_count()) << endl << hash.find(100) << endl;
hash.insert_equal(100);
cout << hash.size() << endl;
hash.insert_unique(100);
cout << hash.size() << endl;
cout << hash.erase(100) << endl;
cout << hash.size();
return 0;
}
hash表 拉鍊法 仿sgi stl 非模板簡單實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.