1. 程式人生 > >HahTable——拉鍊法實現的雜湊表

HahTable——拉鍊法實現的雜湊表

由於雜湊表的查詢高效性,在平時的演算法中用的也是比較多。例如:字串、單詞個數的統計,只出現一次字元或者數字的統計,兩個集合相同元素的查詢等等,還有插入刪除的高效(鏈地址法)都可以用雜湊表來解決。缺點可能是需要佔用額外的記憶體空間。
1 原理分析
處理雜湊衝突的另一種方法是拉鍊法,也稱為雜湊桶。適用於經常進行插入和刪除的情況。一方法參考:https://blog.csdn.net/qq_15000103/article/details/80270964
拉鍊法解決衝突的做法是:將所有關鍵字為同義詞的結點連結在同一個單鏈表中。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指標組成的指標陣列t[0..m-1]。凡是雜湊地址為i的結點,均插入到以t為頭指標的單鏈表中。t中各分量的初值均應為空指標。在拉鍊法中,裝填因子α可以大於1,但一般均取α≤1。
這裡寫圖片描述


2 程式碼實現

//HashTable.h
#pragma once
#include<vector>
#include<utility>
#include<string>

template<class V>
struct HashNode
{
    V _v;//set->k;map->kv
    HashNode<V>* _next;
    HashNode(const V& v)
        :_v(v)
        , _next(NULL)
    {}
};
template<class
K> struct Hash { size_t operator()(const K& key) { return key; } }; template<> struct Hash<string>//特化,使得預設時,若調string,則呼叫此函式 { static size_t BKDRHash(const char * str) { unsigned int seed = 131; // 31 131 1313 13131 131313 unsigned int hash = 0
; while (*str) { hash = hash * seed + (*str++); } return (hash & 0x7FFFFFFF); } size_t operator()(const string& key) { return BKDRHash(key.c_str()); } }; template<class K, class V, class KeyOfValue, class _HashFunc>//unordered_set<K,V>->HashTable<K,K>;unordered_map<K,V>->HashTable<K,pair<K,V>> class HashTable; template<class K, class V, class KeyOfValue, class _HashFunc> struct _HashTableIterator//單向迭代器 { typedef HashNode<V> Node; typedef _HashTableIterator<K, V, KeyOfValue,_HashFunc> Self; typedef HashTable<K, V, KeyOfValue, _HashFunc> HT; Node* _node; HashTable<K, V, KeyOfValue, _HashFunc>* _ht; _HashTableIterator(Node* node, HT* ht) :_node(node) , _ht(ht) {} V& operator*() { return _node->_v; } V* operator->() { return &(operator*()); } Self& operator++() { if (_node->_next) { _node = _node->_next; } else { KeyOfValue kov; size_t index = _ht->HashFunc(kov(_node->_v), _ht->_table.size()); ++index; while (index < _ht->_table.size()) { if (_ht->_table[index]) { _node = _ht->_table[index]; break; } else { ++index; } } if (index == _ht->_table.size()) { _node = NULL; } } return *this; } Self operator++(int) { Self tmp(*this); ++*this; return tmp; } bool operator==(const Self& s ) { return _node == s._node; } bool operator!=(const Self& s) { return _node != s._node; } }; template<class K, class V,class KeyOfValue,class _HashFunc=Hash<K>>//unordered_set<K,V>->HashTable<K,K>;unordered_map<K,V>->HashTable<K,pair<K,V>> class HashTable { typedef HashNode<V> Node; friend struct _HashTableIterator<K, V, KeyOfValue,_HashFunc>; public: typedef _HashTableIterator<K, V, KeyOfValue, _HashFunc> Iterator; Iterator Begin() { for (size_t i = 0; i < _table.size(); i++) { if (_table[i]) { return Iterator(_table[i], this); } } return End(); } Iterator End() { return Iterator(NULL, this); } HashTable() : _size(0) {} bool Insert(const V& v) { CheckCapacity(); KeyOfValue kov; size_t index = HashFunc(kov(v), _table.size()); Node* cur = _table[index]; while (cur) { if (kov(cur->_v) == kov(v)) return false; cur = cur->_next; } Node* node = new Node(v); //頭插 node->_next = _table[index]; _table[index] = node; ++_size; return true; } Node* Find(const K& key) { size_t index = HashFunc(key); Node* cur = _table[index]; KeyOfValue kov; while (cur) { if (kov(cur->_v) == key) { return cur; } cur = cur->_next; } return NULL; } bool Remove(const K& key) { KeyOfValue kov; size_t index = HashFunc(key); Node* cur = _table[index]; if (cur == NULL) { return false; } if (kov(cur->_v) == key)//頭刪 { _table[index] = cur->_next; delete cur; return true; } else//中間刪 { Node* prev = cur; cur = cur->_next; while (cur) { if (kov(cur->_v) == key) { prev->_next = cur->_next; delete cur; return true; } prev = cur; cur = cur->_next; } } return true; } size_t HashFunc(const K& key, size_t size) { _HashFunc hf; return hf(key) % size; } size_t GetNextPrimeNum(size_t num) { const int _PrimeSize = 28; static const unsigned long _PrimeList[_PrimeSize] = { 53ul, 97ul, 193ul, 389ul, 769ul, 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, 1610612741ul, 3221225473ul, 4294967291ul }; for (size_t i = 0; i < _PrimeSize; ++i) { if (_PrimeList[i] > num) { return _PrimeList[i]; } } return _PrimeList[_PrimeSize - 1]; } void CheckCapacity() { if (_table.size() == 0) { _table.resize(GetNextPrimeNum(0), NULL); } else if (_size == _table.size())//考慮負載因子 { size_t newsize = GetNextPrimeNum(_table.size()); if (newsize = _table.size()) { return; } vector<Node*> newtable; newtable.resize(newsize, NULL); KeyOfValue kov; for (size_t i = 0; i < _table.size(); ++i) { Node* cur = _table[i]; while (cur) { size_t index = HashFunc(kov(cur->_v), newsize); Node* next = cur->_next; //頭插到newtable; cur->_next = newtable[index];//將cur指向新表的位置 newtable[index] = cur; cur = next; } _table[i] = NULL; } _table.swap(newtable); } } private: std::vector<Node*> _table; size_t _size; }; template<class K> struct SetKeyOfValue { const K&operator()(const K& key) { return key; } }; template<class K,class V> struct MapKeyOfValue { const K&operator()(const std::pair<K,V>& kv) { return kv.first; } };

測試程式碼:

//test.cpp
#include<iostream>
#include<utility>
#include"HashTable.h"
#include<string>
using namespace std;
void TestHashTable()
{
    typedef  HashTable<int, int, SetKeyOfValue<int>> IntSet;
    typedef  HashTable<int, int, SetKeyOfValue<int>>::Iterator IntSetIter;
    IntSet ht;
    ht.Insert(4);
    ht.Insert(14);
    ht.Insert(24);
    ht.Insert(33);
    ht.Insert(55);
    ht.Insert(19);
    ht.Insert(55);
    IntSetIter it = ht.Begin();
    while (it != ht.End())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    typedef  HashTable<string, string, SetKeyOfValue<string>> StringSet;
    typedef  HashTable<string, string, SetKeyOfValue<string>>::Iterator StringSetIter;
    StringSet ss;
    ss.Insert("sort");
    ss.Insert("left");
    ss.Insert("string");
    ss.Insert("char");
    ss.Insert("char");

    StringSetIter it1 = ss.Begin();
    while (it1!=ss.End())
    {
        cout << *it1 << " ";
        ++it1;
    }
    cout << endl;
}
int main()
{
    TestHashTable();
    system("pause");
    return 0;
}

執行結果如下:
這裡寫圖片描述