財神娛樂首存即享優惠回饋唷~詳情請進👉

【數據布博亦局】哈希表

大樂透加碼

哈希表(散列表),是經由過程樞紐字key而間接走訪在內存存儲地位的一種數據布局,它便是 以空間換取時間。經由過程多開拓幾個空間,來完成查找的高效率。
關于哈希表,咱們并不是很目生:在c說話進修階段,給定一個字符串,查找第一個只浮現過一次的字符;在數據布局 矩陣的高效轉置要領中,計算原矩陣中每一列中有用數字的個數;在文件壓縮項目(以后給出闡發總結)中,計算中文件中各個字符浮現的次數。
關于組織哈希表,有如下幾種要領:
1)間接定址法:取樞紐字key的某個線性函數為散列地址
2)除留余數法:散列地址為,key模一個小于或者者即是表長的數,若是key不是整數,可以經由過程種種路子轉換,下邊先容~~
3)折疊法
4)平方取中法
5)隨機數法
6)數學闡發法
下邊的幾種要領,只要要曉得就好~~重點把握前兩種~
關于間接定址法,給定一個key,就可以對應一個地址(這類比較實用于key值比較集中的環境,若是key值過于疏散,就必要鋪張許多空間)
關于除留余數法,不同的key有可能對應統一個散列地址。當多個key對應一個散列地址值時,如許就產生了沖突,這類沖突鳴做哈希沖突或者者哈希碰撞。
既然有了沖突,咱們該若何辦理沖突呢???這里就會有幾種要領:
1)線性探測:關于一個給定的key,當有其它key值占了它的散列地址的地位,他就應當以線性方式往找下一個空地置
2)二次探測:現實是二次方探測,當產生沖突時,以二次方的方式往找下一個空地置。
3)開鏈法:
下邊給出以上三種設施的圖形詮釋:

為了防止哈希沖突,咱們引入了負載因子這一律念,負載因子便是哈希表中元素的個數與哈希表的巨細的比值便是負載因子。關于凋謝定址法,大樂透獎金分配載荷因子是分外緊張身分,應將其節制在0.7–0.8如下,查過0.8,查表時,CPU的緩存不擲中。(cache的使用,辦理了主存速率不敷的成績。當CPU要讀取一段數據時,先在cache中查找,若是找到了,申明擲中;若是找不到,往主存中查找,然后依據調度算法將要讀取的數據從主存調入cache)。。
咱們平日將哈希表的巨細配置為素數,如許也是可以防止沖突的。
若是哈希表中的數組的容量不是素數,假定要拔出的元素是10,20,30,40,哈希表的巨細是10,失去1種hash值,0。若是要拔出的元素是3,6,9,12,而hash表的巨細是9,失去3種hash值,0,3,6。如許,就致使沖突仍是比較大的。。。。。此處證實不是很謹嚴,只是簡略申明了一下。
為了到達主動擴展容量的作用,咱們哈希表的底層用vector代替數組~
下邊給出完成代碼:

#pragma once
#include<iostream>
using namespace std;
#include<vector>
#include<string>

//凋謝地址法
namespace Open
{
    enum Status
    {
        EMPTY,EXIST,DELETE
    };


    template<typename K,typename V>
    struct KVNode
    {
        K _key;
        V _value;

        Status _status;//保管某個地位的狀況
        KVNode(const K& key = K(),const V& value = V())
            :_key(key),_value(value),_status(EMPTY)
        {}
    };
    template<typename K>
    struct __GetK
    {
        size_t operator()(const K& key)
        {
            return key;
        }
    };

    struct __GetStrK
    {
        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& str)
        {
            return BKDRHash(str.c_str());
        }
    };

    template<typename K,typename V,typename GetK = __GetK<K>>
    class HashTable
    {
        typedef KVNode<K,V> Node;

    public:
        HashTable()
            :_size(0)
        {
            _tables.resize(2);
        }

        ~HashTable()
        {}


        void Swap(HashTable<K,V,GetK> ht)
        {
            swap(_size,ht._size);
            swap(_tables,ht._tables);
        }

        bool Insert(const K& key,const V& value)
        {
            _CheckCapacity();
            int index = _GetIndex(key,value);

            while(_tables[index]._status == EXIST)
            {
                if(_tables[index]._key == key)//要拔出的值在原表中已經經存在
                {
                    return false;
                }

                ++index;

                if(index == _tables.size())
                {
                    index = 0;
                }
            }

            //找到合適的地位
            _tables[index]._key = key;
            _tables[index]._value = value;
            _tables[index]._status = EXIST;//將狀況改成存在
            ++_size;
        }

        Node* Find(const K& key,const V& value)
        {
            int index = _GetIndex(key,value);
            int begin = index;
            while(_tables[index]._key != key)
            {
                ++index;
                if(index == _tables.size())
                {
                    index = 0;
                }
                if(index == begin)
                {
                    return NULL;
                }
            }
            //有多是要刪除的已經經存在的元素
            if(_tables[index]._status == EXIST)
            {
                return &_tables[index];
            }
            else
                return NULL;
        }

        bool Remove(const K& key,const V& value)
        {
            if(_size == 0)
                return false;
            int index = _GetIndex(key,value);
            int begin = index;
            while(_tables[index]._status != EMPTY)
            {
                if(_tables[index]._key == key && _tables[index]._status == EXIST)
                {
                    _tables[index]._status = DELETE;
                    --_size;
                    return true;
                }

                ++index;
                if(index == _tables.size())
                {
                    index = 0;
                }
                if(index == begin)//已經經遍歷一圈
                {
                    return false;
                }
            }
        }
    protected:
        void _CheckCapacity()
        {
            if(_size*10 / _tables.size() >= 8)//保障查找效率
            {
                int newSize = _GetNewSize(_tables.size());
                HashTable<K,GetK> hash;
                hash._tables.resize(newSize);
                for(size_t i = 0; i < _size; ++i)
                {
                    if(_tables[i]._status == EXIST)
                    {
                        hash.Insert(_tables[i]._key,_tables[i]._value);
                    }
                }
                this->Swap(hash);
            }
            else
                return;
        }

        int _GetIndex(const K& key,const V& value)
        {
            GetK getK;
            return getK(key) % _tables.size();
        }
        int _GetNewSize(int 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(int i = 0; i < _PrimeSize; ++i)
            {
                if(_PrimeList[i] > num)
                    re九牛娛樂城turn _PrimeList[i];
            }
        }
    protected:
        vector<Node> _tables;
        size_t _size;
    };
}


void TestHashTableOpen()
{
    Open::HashTable<int,int>  ht1;//模板參數3是采取缺省的參數
    int array1[] = {89,18,8,58,2,3,4,9,0};
    for(int i = 0; i < sizeof(array1)/sizeof(array1[0]); ++i)
    {
        ht1.Insert(array1[i],0);
    }
    ht1.Remove(8,0);
    ht1.Remove(1,0);

    Open::HashTable<string,int,Open::__GetStrK> ht2;
    char* array2[] = {"大眾hello"大眾,"大眾world"大眾,"大眾sort"大眾,"大眾find"大眾,"大眾sort"大眾};
    for(int i = 0; i < sizeof(array2)/sizeof(array2[0]); ++i)
    {
        Open::KVNode<string,int>* node = ht2.Find(array2[i],0);
        if(node)//結點已經經存在
        {
            node->_value++;
        }
        else
        {
            ht2.Insert(array2[i],0);
        }
    }
}


//開鏈法
namespace Link
{
    template<typename K,typename V>
    struct KVNode
    {
        K _key;
        V _value;
        KVNode<K,V>* _next;

        KVNode(const K& key = K(),const V& value = V())
        :_key(key),_next(NULL)
        {}
    };

    template<typenam妞妞撲克牌ptte K>
    struct __GetK
    {
        size_t operator()(const K線上真人麻將推薦& key)
        {
            return key;
        }
    };

    template<>
    struct __GetK<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& str)
        {
            return BKDRHash(str.c_str());
        }
    };

    template<typename K,V> Node;
    public:
        HashTable()
            :_size(0)
        {
            _tables.resize(2);//初始化開拓2個空間
        }

        bool Insert(const K& key,const V& value)
        {
            //反省容量
            _CheckCapacity();
            int index = _GetIndex(key);
            //先查找,望要拔出的元素是否已經經存在
            if(Find(key))
            {
                return false;
            }
            //拔出元素分兩種環境
            //1.拔出的結點是第一個結點
            //2.拔出的結點不是第一個結點
            Node* newNode = new Node(key,value);
            newNode->_next = _tables[index];
            _tables[index] = newNode;
            ++_size;
        }

        Node* Find(const K& key)
        {
            int index = _GetIndex(key);
            Node* cur = _tables[index];
            while(cur)
            {
                if(cur->_key == key)
                    return cur;
                cur = cur->_next;
            }
            return NULL;
        }

        bool Remove(const K& key)
        {
            int index = _GetIndex(key);
            //刪除分3種環境
            //1.刪除第一個節點
            //2.刪除中間結點
            //3.刪除最初一個結點
            Node* cur = _tables[index];
            //記載要刪除結點的上一個結點
            Node* prev = NULL;
            while(cur)
            {
                if(cur->_key == key)//找到要刪除的結點
                {
                    if(prev == NULL)//要刪除的便是第一個結點
                    {
                        _tables[index] = cur->_next;
                    }
                    else
                    {
                        prev->_next = cur->_next;
                    }
                    delete cur;
                    --_size;
                    return true;
                }
                prev = cur;
                cur = cur->_next;
            }
            return false;
        }

    protected:
        int _GetIndex(const K& key)
        {
            GetK getK;
            return getK(key) % _tables.size();
        }

        void _CheckCapacity()
        {
            if(_size == _tables.size())
            {
                int newSize = _GetNewSize(_size);//容量擴展
                HashTable<K,GetK> tmp;
                tmp._tables.resize(newSize);
                vector<K> v;
                Node* del = NULL;

                //把一切元素放進vector中
                for(size_t i = 0; i < _size; ++i)
                {
                    //找到有存儲元素的鏈
                    if(_tables[i] != NULL)
                    {
                        Node* cur = _tables[i];
                        while(cur)
                        {
                            //cur = _tables[i];
                            v.push_back(cur->_key);
                            cur = cur->_next;
                        }

                        //清理空間
                        cur = _tables[i];
                        while(cur)
                        {
                            del = cur;
                            cur = cur->_next;
                            delete del;
                        }
                    }
                    else
                        continue;
                }
                //將vector中的一切元素從新拔出
                for(size_t i = 0 ; i < v.size(); ++i)
                {
                    tmp.Insert(v[i],0);
                    //v.pop_back();
                }
                //已經經挪移實現
                this->_Swap(tmp);
            }
        }

        int _GetNewSize(int num)
        {
            const int _PrimeSize= 28;
            static const unsigned long _PrimeList[_PrimeSize] = {
            53ul,4294967291ul
            };
            for(int i = 0; i < _PrimeSize; ++i)
            {
                if(_PrimeList[i] > num)
                    return _PrimeList[i];
            }
        }

        void _Swap(HashTable<K,GetK> ht)
        {
            swap(ht._tables,_tables);
            swap(ht._size,_size);
        }

    protected:
        vector<Node* > _tables;
        size_t _size;
    };

}
void TestHashTableLink()
{
    Link::HashTable<int,int>  ht1;
    int array1[] = {89,21,53,12,0);
    }
    ht1.Remove(4);
    ht1.Remove(12);

    Link::HashTable<string,int> ht2;
    char* array2[] = {"大眾hello公眾,公眾yang"大眾,"大眾hello公眾,"大眾wang"大眾,"大眾zip公眾,"大眾huffman公眾};
    for(int i = 0; i < sizeof(array2)/sizeof(array2[0]); ++i)
    {
        Link::KVNode<string,int>* ret = ht2.Find(array2[i]);
        if(!ret)
            ht2.Insert(array2[i],0);
    }
    ht2.Remove("大眾hello公眾);
    ht2.Remove("大眾sort公眾);
}

【免責聲明】本站內容轉載自互聯網,其相關談吐僅代表作者小我私家概念盡非權勢巨子,不代表本站態度。如您發明內容存在版權成績,請提交相關鏈接至郵箱:,咱們將實時予以處置。