hash表 拉鍊法 仿sgi stl 非模板簡單實現

#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;
}

發佈了51 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章