溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

【數(shù)據(jù)結(jié)構(gòu)】處理哈希沖突的開(kāi)鏈法(哈希桶)算法實(shí)現(xiàn)

發(fā)布時(shí)間:2020-06-19 19:16:58 來(lái)源:網(wǎng)絡(luò) 閱讀:1210 作者:韓靜靜 欄目:編程語(yǔ)言

實(shí)現(xiàn)哈希表時(shí),我們常見(jiàn)的方法是線性探測(cè)、二次探測(cè),這兩個(gè)算法也很簡(jiǎn)單。若有興趣,可以查看我的博客 http://10740184.blog.51cto.com/10730184/1771160。但是,這兩個(gè)算法有一個(gè)共同點(diǎn)就是:空間利用率低。為什么這么說(shuō)呢?線性探測(cè)、二次探測(cè)的高效性很大程度上要取決于它的載荷因子,載荷因子即:存放關(guān)鍵字個(gè)數(shù)/空間大小。


通過(guò)查閱資料,我發(fā)現(xiàn),使用素?cái)?shù)做除數(shù)可以減少哈希沖突(具體原因不詳,大師專研的,發(fā)現(xiàn)很好用,就在這里分享給大家)。見(jiàn)下:

----素?cái)?shù)表

     // 使用素?cái)?shù)表對(duì)齊做哈希表的容量,降低哈希沖突

     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

    };



開(kāi)鏈法(哈希桶)結(jié)構(gòu):

【數(shù)據(jù)結(jié)構(gòu)】處理哈希沖突的開(kāi)鏈法(哈希桶)算法實(shí)現(xiàn)而哈希桶實(shí)現(xiàn)時(shí),我們可以將載荷因子設(shè)成1.


代碼如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

#include<vector>

template<class K,class V>
struct HashTableNode
{
    K _key;
    V _value;
    HashTableNode* _next;
    HashTableNode(const K& key,const V& value)
        :_key(key)
        , _value(value)
        , _next(NULL)
    {}
};

template<class K,class V>
class HashTable
{
public:
    typedef HashTableNode<K,V> Node;

    HashTable()
        :_table(NULL)
        , _size()
    {}


    size_t _HashFunc(const K& key)
    {
        //_table.size()表示哈希桶的空間大小
        return key % _table.size();
    }
    
    
    //拷貝構(gòu)造
    HashTable(const HashTable& ht)
    {
        //將哈希表ht拷貝給this
        this->_table.resize(ht._table.size());
        for (int i = 0; i < ht._table.size(); i++)
        {
            Node* cur = ht._table[i];
            while (cur)
            {
                Node* tmp = new Node(cur->_key, cur->_value);
                tmp->_next = _table[i];
                _table[i] = tmp;
                this->_size++;

                cur = cur->_next;
            }
        }    
    }


    HashTable<K, V> operator=(const HashTable<K, V>& ht)
    {    
        if (&ht != this)
        {
            //刪除哈希表this
            for (int i = 0; i < this->_table.size(); i++)
            {
                Node* cur = _table[i];
                while (cur)
                {
                    Node* del = cur;
                    cur = cur->_next;
                    /*delete del;
                    del = NULL;*/
                    Remove(del->_key);
                }
            }

            //將哈希表ht拷貝給this
            this->_table.resize(ht._table.size());
            for (int i = 0; i < ht._table.size(); i++)
            {
                Node* cur = ht._table[i];
                while (cur)
                {
                    Node* tmp = new Node(cur->_key, cur->_value);
                    tmp->_next = _table[i];
                    _table[i] = tmp;
                    this->_size++;

                    cur = cur->_next;
                }
            }        
        }
        return *this;
    }


    //賦值運(yùn)算符重載的現(xiàn)代寫法
    HashTable<K, V> operator=(HashTable<K, V> ht)
    {
        if (&ht != this)
        {
            swap(_table, ht._table);
            swap(_size, ht._size);
        }    
        return *this;
    }


    ~HashTable()
    {
        //刪除哈希表ht
        if (this->_table.size() !=0)
        {
            for (int i = 0; i < this->_table.size(); i++)
            {
                Node* cur = _table[i];
                while (cur)
                {
                    Node* del = cur;
                    cur = cur->_next;
                    delete del;
                    del = NULL;
                }
            }
        }
    }


    //獲取新的哈希表容量大小
    size_t _GetnewSize()
    {
        static 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 (int i = 0; i < _PrimeSize; i++)
        {
            if (_PrimeList[i]> _table.size())
            {
                return _PrimeList[i];
            }
        }
        return _PrimeList[_PrimeSize - 1];
    }


    //給哈希桶擴(kuò)容
    void _ExpandCapacity()
    {        
        //開(kāi)辟新的更大容量的哈希表
        size_t newSize = _GetnewSize();
        vector<Node*> newTable;
        newTable.resize(newSize);

        //將每處順序表上的單鏈表元素摘下來(lái)插入到新的順序表上
        for (int i = 0; i < _table.size(); i++)
        {
            Node* cur = _table[i];
            while (cur)
            {
                Node* tmp = cur;
                cur = cur->_next;
                int index = _HashFunc(tmp->_key);
                //頭插法插插節(jié)點(diǎn)
                tmp->_next = newTable[index];
                newTable[index] = tmp;
            }
            _table[i] = NULL;
        }
        _table.swap(newTable);
    }


    //插入關(guān)鍵字
    bool Insert(const K& key,const V& value)
    {
        //檢查載荷因子,考慮是否擴(kuò)容
        //哈希桶的載荷因子設(shè)置為1
        if (_size == _table.size())
        {
            _ExpandCapacity();
        }

        //往順序表的index處插入節(jié)點(diǎn)
        size_t index = _HashFunc(key);
        Node* begin = _table[index];
        while (begin)
        {
            //設(shè)計(jì)成不可出現(xiàn)重復(fù)元素
            if (begin->_key == key)
            {
                return false;
            }

            begin = begin->_next;
        }

        //考慮到同一條單鏈表上,無(wú)所謂元素存放順序,且較尾插簡(jiǎn)單。--》頭插
        Node* tmp = new Node(key, value);
        tmp->_next =_table[index];
        _table[index] = tmp;
        _size++;
        return true;
    }


    //查找關(guān)鍵字
    Node* Find(const K& key)
    {
        int index = _HashFunc(key);
        Node* cur = _table[index];
        while (cur)
        {
            if (cur->_key == key)
                return cur;
            cur = cur->_next;
        }
        return NULL;
    }


    //刪除關(guān)鍵字
    bool Remove(const K& key)
    {
        int index = _HashFunc(key);
        Node* cur = _table[index];
        Node* prev = NULL;
        while (cur)
        {
            if (cur->_key == key)
                break;
            prev = cur;
            cur = cur->_next;
        }

        if (cur)
        {
            if (cur == _table[index])
            {            
                _table[index] = cur->_next;
            }
            else
            {
                Node* next = cur->_next;
                prev->_next = next;
            }
            delete cur;
            cur = NULL;
            --_size;
            return true;        
        }
        return false;
    }


    //打印哈希桶
    void PrintHashTable()
    {
        for (int i = 0; i < _table.size(); i++)
        {
            Node* cur = _table[i];
            cout << i<<":" ;
            while (cur)
            {
                cout << cur->_key << "->";
                cur = cur->_next;
            }
            cout << "NULL" << endl;
        }
        cout << endl;
    }
    
private:
    vector<Node*> _table;
    size_t _size;//數(shù)據(jù)個(gè)數(shù)
};


void TestHashTableBucket()
{
    typedef HashTableNode<int, char> Node;

    HashTable<int, char> ht;
    ht.Insert(1, 'a');
    ht.Insert(2, 'b');
    ht.Insert(3, 'c');
    ht.Insert(4, 'd');
    ht.Insert(5, 'd');
    ht.Insert(54, 'x');
    ht.Insert(55, 'y');
    ht.Insert(56, 'z');

    ht.PrintHashTable();


    /*Node* ret = ht.Find(5);
    cout << ret->_value << endl;

    ht.Remove(1);
    ht.Remove(6);
    ht.PrintHashTable();*/

    /*HashTable<int, char> ht1(ht);
    ht1.PrintHashTable();*/

    HashTable<int, char> ht2;
    ht2.Insert(54, 'x');
    ht2.Insert(55, 'y');
    ht2.Insert(56, 'z');
    ht2.Insert(1, 'a');
    ht2.Insert(2, 'b');
    ht2.Insert(3, 'c');
    ht2.Insert(4, 'd');
    ht2.Insert(5, 'd');

    ht2.PrintHashTable();

    ht = ht2;
    ht.PrintHashTable();

}


int main()
{
    TestHashTableBucket();
    system("pause");
    return 0;
}


向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI