HashTble data structures (hash table) to achieve a simple application ---- simple hash table using hash map

With a simple hash table to achieve hash map

Reference Site

  1. https://blog.csdn.net/stpeace/article/details/81274233
  2. https://blog.csdn.net/qq_36221862/article/details/73488162
  3. https://blog.csdn.net/xyzbaihaiping/article/details/51607770

Theoretical knowledge hash table

Here are the basics of the relationship between the hash table is not elaborated

Simple application of the hash table

Simple hash table to achieve HashMap (zipper method) based on

Code for reference only: GitHub address

#include <iostream>
#include <string>
#include <memory>
#include <functional>

using namespace std;

//hash table 内部节点
template <typename T,typename U>
class Node{
public:
    Node(const T& key,const T& value){
        m_key = key;
        m_value = value;
    }
    ~Node(){
        std::cout<<"~Node()"<<std::endl;
    }
public:
    T m_key;
    U m_value;
    std::unique_ptr<Node<T,U>> pNode = nullptr; //内存是否能回收?
};

//基于hash table 实现的HashMap 冲突解决使用拉链法
template <typename T,typename U>
class HashMap{
public:
    explicit HashMap(const unsigned int size){
        this->m_size = size;
        m_ppNode = std::make_unique<unique_ptr<Node<T,U>>[]>(m_size);
        for(unsigned int index=0;index<m_size;index++){
            m_ppNode[index].reset(nullptr);
        }
    }
public:
    void Insert(const T& key,const U& value){
        int index = std::hash<T>{}(key)%m_size; //std::hash C++ 17
        std::unique_ptr<Node<T,U>> newNode = std::make_unique<Node<T,U>>(key,value);
        if(m_ppNode[index] == nullptr){
            m_ppNode[index] = std::move(newNode);//内存是否被正确回收?待验证
            return ;
        }
        //map容器考虑去重
        Node<T,U>* node = m_ppNode[index].get();
        while(node->pNode!= nullptr){
            if(node->m_key == key){
                node->m_value = value;
                return;
            }
            node = node->pNode.get();
        }
        if(node->m_key == key){ //判断循环最后一个元素
            node->m_value = value;
            return ;
        }
        //没有重复的元素 采用尾插法
        node->pNode = std::move(newNode);
    }

    pair<U,bool> Find(const T&key){
        int index = std::hash<T>{}(key)%m_size;
        auto p = m_ppNode[index].get();
        while(p!= nullptr){
            if(p->m_key == key){
                return make_pair(p->m_value, true);
            }
            p = p->pNode.get();
        }
        return make_pair(U(), false);
    }
private:
    std::unique_ptr<unique_ptr<Node<T,U>>[]> m_ppNode = nullptr;//unique_ptr对象数组
    unsigned int m_size=0;
};

int main() {
    {
        HashMap<string,string> map(100);
        map.Insert("a","aaa");
        map.Insert("b","bbb");

        pair<string,bool> ret1 = map.Find("a");
        if(ret1.second){
            std::cout<<"find:value="<<ret1.first<<std::endl;
        } else{
            std::cout<<"not find"<<std::endl;
        }

        pair<string,bool> ret2 = map.Find("b");
        if(ret2.second){
            std::cout<<"find:value="<<ret2.first<<std::endl;
        } else{
            std::cout<<"not find"<<std::endl;
        }

        pair<string,bool> ret3 = map.Find("c");
        if(ret3.second){
            std::cout<<"find:value="<<ret3.first<<std::endl;
        } else{
            std::cout<<"not find"<<std::endl;
        }
    }
    return 0;
}

Simple implementation of the HashMap hash table (linear probe method, a second probe method) based

Code for reference only: GitHub address

#include <iostream>
#include <string>
#include <vector>

using namespace std;

enum State{
    EMPTY,
    DELETE,
    EXIST
};

//hash table 内部节点
template <typename K,typename V>
class HashNode{
public:
    HashNode():m_state(EMPTY){}
public:
    std::pair<K,V> m_kv;
    State m_state;
};

//基于hash table 实现的HashMap 冲突解决使用开放地址法
template <typename K,typename V,bool isLine = true> //模板偏特化
class HashMap{
public:
    explicit HashMap(const unsigned int size = 10):m_size(0){
        m_table.resize(GetNextPrime(size));
    }
public:
    bool Insert(const K& key,const V& value){
        CheckSize();
        unsigned int hashAddr = std::hash<K>{}(key)%m_table.size();//C++ 17
        unsigned int index = hashAddr;
        unsigned int i = 1;
        while(m_table[index].m_state == EXIST){
            if(m_table[index].m_kv.first == key){
                return false;
            }
            if(isLine){
                index = DetectedLine(index);
            }else{
                index = DetectedSquare(index,i++);
            }
        }
        m_table[index].m_kv = std::make_pair(key,value);
        m_table[index].m_state = EXIST;
        m_size++;
        return true;
    }

    std::pair<HashNode<K,V>*,bool> Find(const K&key){
        unsigned int hashAddr = std::hash<K>{}(key)%m_table.size();//C++ 17
        unsigned int index = hashAddr;
        HashNode<K, V>& elem = m_table[index];
        if(elem.m_kv.first!=key){ //产生冲突了 继续寻找
            if(isLine){//线性查找
                while(true){
                    index = DetectedLine(index);
                    if(index == hashAddr){
                        return std::make_pair(&elem,false);
                    }
                    if(m_table[index].m_kv.first == key && m_table[index].m_state == EXIST){
                        return std::make_pair(&m_table[index], true);
                    }
                }
            }else{//平方查找
                unsigned int i = 1;
                while(m_table[index].m_state != EMPTY){ //EXIST和DELETE都是要查找的目标
                    index = DetectedSquare(index,i++);
                    if(m_table[index].m_kv.first == key && m_table[index].m_state == EXIST){
                        return std::make_pair(&m_table[index], true);
                    }
                }
            }
        }else{
            if(m_table[index].m_state == EXIST){
                return make_pair(&elem, true);
            }
        }

        return make_pair(&elem, false);
    }

    bool Remove(const K& key){
        auto ret = Find(key);
        if(ret.second){
            ret.first->m_state = DELETE;
            m_size--;
            return true;
        }
        return false;
    }

    inline unsigned int Size(){
        return m_size;
    }

private:
    unsigned int DetectedLine(unsigned int hashAddr){ //线性探查法
        hashAddr++;
        if(hashAddr == m_table.size()){
            hashAddr = 0;
        }
        return hashAddr;
    }

    unsigned int DetectedSquare(unsigned int hashAddr, unsigned int i){//平方探查法
        /*
         * H(i) = H0 + i^2
         * H(i-1) = H0 + (i-1)^2
         * H(i) = H(i-1) + 2*i - 1 = H(i-1) + i<<1 - 1
         * */
        hashAddr = hashAddr + 2*i - 1;
        hashAddr = hashAddr % m_table.size() ;
        return hashAddr;
    }

    void CheckSize(){
        if(m_size/m_table.size()*10>=6){ //当装载因子a大于0.5时,需要将vector扩容处理
            m_table.resize(GetNextPrime(m_size));

            HashMap<K,V,isLine> hm;
            for(auto it : m_table){
                if(it.m_state == EXIST){
                    hm.Insert(it.m_kv.first,it.m_kv.second);
                }
            }
            this->Swap(hm);
        }
    }

    void Swap(HashMap<K,V,isLine> hm){
        std::swap(m_size,hm.m_size);
        m_table.swap(hm.m_table);
    }

    unsigned int GetNextPrime(const unsigned int size){//使用素数表对齐做哈希表的容量,降低哈希冲突
        const int _PrimeSize = 28;
        static const unsigned long _PrimeList[_PrimeSize] ={
                52ul, 97ul, 193ul, 389ul, 769ul,
                1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
                49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
                1572869ul, 3145739ul, 6291469ul, 12582917ul, 24165843ul,
                50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
                1610612741ul, 3221225473ul, 4294967291ul
        };

        for(unsigned i = 0; i < _PrimeSize; ++i){
            if (_PrimeList[i] > size){
                return _PrimeList[i];
            }
        }
        return _PrimeList[_PrimeSize-1];
    }

private:
    std::vector<HashNode<K,V>> m_table; //hash table
    unsigned int m_size=0;//hash table store element number
};

int main() {
    {
        HashMap<int,int,false> map;
        map.Insert(25, 1);
        map.Insert(25, 2);
        map.Insert(14, 2);
        map.Insert(36, 3);
        map.Insert(49, 4);
        map.Insert(68, 5);
        map.Insert(57, 6);
        map.Insert(11, 7);
        map.Insert(37, 8);

        cout<<map.Size()<<endl;

        auto ret = map.Find(25);
        if(ret.second){
            std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
        }else{
            std::cout<<"not find"<<std::endl;
        }

        ret = map.Find(11);
        if(ret.second){
            std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
        }else{
            std::cout<<"not find"<<std::endl;
        }

        ret = map.Find(12);
        if(ret.second){
            std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
        }else{
            std::cout<<"not find:12"<<std::endl;
        }

        map.Remove(25);
        ret = map.Find(25);
        if(ret.second){
            std::cout<<"Find:key="<<ret.first->m_kv.first<<" value="<<ret.first->m_kv.second<<std::endl;
        }else{
            std::cout<<"not find:25"<<std::endl;
        }

        map.Remove(14);
        cout<<map.Size()<<endl;
    }
    return 0;
}
Published 155 original articles · won praise 15 · views 160 000 +

Guess you like

Origin blog.csdn.net/wangdamingll/article/details/104198484
Recommended