zoukankan      html  css  js  c++  java
  • hashmap的C++实现

    hashmap的C++实现

    按照hashmap的基本原理用C++实现了简单的基本功能,复杂的实现参考C++库的源码,C++最新的标准库里已经有以下四种基于hashtable的容器:

    unordered_set (C++11) unordered_multiset (C++11) unordered_map (C++11) unordered_multimap (C++11)。具体参考:http://en.cppreference.com/w/

    /*
     * HashMap.h
     * Author: luxiaoxun
     */
    
    #ifndef HASHMAP_H_
    #define HASHMAP_H_
    
    #include <iostream>
    using namespace std;
    
    //List all the integer number no less than 57 total number is 28
    //And each number is about half of its next number
    static int prime[28] =
    {
        57,        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
    };
    
    class HashMapUtil
    {
    public:
        static int find_NextPrimeNumber(int current)
        {
            //Find the next prime number by searching in the prime number list
            int i = 0;
            for( ; i < 28 ; i++ )
                if(current < prime[i])
                    break;
            return prime[i];     //return the next larger prime.
        }
    };
    
    template <class Key, class Value, class HashFunc, class EqualKey>
    class HashMap
    {
    private:
        template <class _Key, class _Value>
        class KeyNode
        {
            public:
            _Value  value;      //Store the value
            _Key    key;        //Store the keyword
            int    used;
            //if the type of Value/Key is your own class, make sure they can handle copy constructor and operator =
            KeyNode():used(0){}
            KeyNode(const KeyNode & kn)
            {
                value = kn.value;
                key = kn.key;
                used = kn.used;
            }
            KeyNode & operator=(const KeyNode & kn)
            {
                if(this == &kn) return *this;
                value = kn.value;
                key = kn.key;
                used = kn.used;
                return *this;
            }
        };
    
    public:
        HashMap();
        ~HashMap();
        bool insert(const Key& hashKey, const Value& value);
        bool remove(const Key& hashKey);
        void rehash();  //use it when rehashing
        Value& find(const Key& hashKey);
        const Value& operator [](const Key& hashKey) const;
        Value& operator [](const Key& hashKey);
    
    private:
        HashFunc hash;
        EqualKey equal;
        HashMapUtil hml;
        KeyNode<Key ,Value> *table;
        int size;    //current number of itmes
        int capacity;   //capacity of the array
        static const double loadingFactor;
        int findKey(const Key& hashKey);  //find the index of a key
    };
    
    template<class Key , class Value , class HashFunc , class EqualKey>
    const double HashMap<Key, Value, HashFunc, EqualKey>::loadingFactor = 0.9;
    
    template<class Key , class Value , class HashFunc , class EqualKey>
    HashMap<Key, Value, HashFunc, EqualKey>::HashMap()
    {
        hash = HashFunc();
        equal = EqualKey();
        hml = HashMapUtil();
        capacity = hml.find_NextPrimeNumber(0); //initialize the capacity with first primer 57
        //resize the table with capacity because an extra one is used
        //to return the NULL type of Value in the function find
        table = new KeyNode<Key,Value>[capacity+1];
        for(int i = 0 ; i < capacity ; i++)    //initialize the table
            table[i].used = 0;
        size = 0;
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    HashMap<Key, Value, HashFunc, EqualKey>::~HashMap()
    {
        delete []table;
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    bool HashMap<Key, Value, HashFunc, EqualKey>::insert(const Key& hashKey, const Value& value)
    {
        int index = hash(hashKey)%capacity;
        //cout<<"Index is "<<index<<endl;
        if(table[index].used == 1)  //the key-value's hash is unique
        {
            //cout<<"The key-value must be unique!"<<endl;
            return false;
        }
        table[index].used = 1;         //modify the KeyNode
        table[index].key = hashKey;
        table[index].value = value;
    
        size++;
        //if the table's size is too large ,then rehash it
        if (size >= capacity * loadingFactor)
            rehash();
        return true;
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    void HashMap<Key, Value, HashFunc, EqualKey>::rehash()
    {
        int pastsize = capacity;
        //create a new array to copy the information in the old table
        capacity = hml.find_NextPrimeNumber(capacity);
        KeyNode<Key,Value>* tmp = new KeyNode<Key,Value>[capacity];
        for(int i = 0 ; i < pastsize ; i++)
        {
            if(table[i].used == 1)       //copy the KeyNode into the tmp array
            {
                tmp[i] = table[i];
            }
        }
        delete []table; //release the memory of the old table
    
        table = new KeyNode<Key,Value>[capacity+1];   //resize the table
        for(int i = 0 ; i < capacity ; i++) //initialize the table
        {
            table[i].used = 0;
        }
        for(int i = 0 ; i < pastsize ; i++) //insert the item into the table one by one
        {
            if(tmp[i].used == 1)
                insert(tmp[i].key, tmp[i].value);
        }
        delete []tmp;               //delete the tmp array
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    bool HashMap<Key, Value, HashFunc, EqualKey>::remove(const Key& hashKey)
    {
        int index = findKey(hashKey); //find the index of the key
        if(index < 0) //if find modify the flag with 0,else print out "no such key!"
        {
            cout<<"No such Key!"<<endl;
            return false;
        }
        else
        {
            table[index].used = 0;
            size--;
            return true;
        }
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    Value& HashMap<Key, Value, HashFunc, EqualKey>::find(const Key& hashKey)
    {
        int index = findKey(hashKey);
        if(index < 0) //if index <0 ,not found,else return the index
        {
            cout<<"can not find the key!"<<endl;
            return table[capacity].value; //return NULL
        }
        else
        {
            return table[index].value;
        }
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    const Value& HashMap<Key, Value, HashFunc, EqualKey>::operator[](const Key& hashKey) const
    {
        return find(hashKey); //overload the operation to return the value of the element
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    Value& HashMap<Key, Value, HashFunc, EqualKey>::operator[](const Key& hashKey)
    {
        return find(hashKey); //overload the operation to return the value of the element
    }
    
    template<class Key, class Value, class HashFunc, class EqualKey>
    int HashMap<Key, Value, HashFunc, EqualKey>::findKey(const Key& hashKey)
    {
        int index = hash(hashKey)%capacity;
        if ((table[index].used != 1) || !equal(table[index].key,hashKey))
            return -1;
        else
            return index;
    }
    
    #endif /* HASHMAP_H_ */

    这里实现的key必须是unique的,否则就要处理冲突的问题,可以通过[]操作修改对应的value,但是不能通过[]添加value,标准库里的是可以的。

    C++编译器不支持模板头文件和实现代码分离的编译,如果的类实现和类声明分别放在cpp文件和h头文件里,那么在测试代码里include要加上实现的代码,比如加上#include"HashMap.cpp"。使用hashmap,需要自己提供针对key的hash函数对象和equal函数对象,测试代码:

    #include "HashMap.h"
    #include <string>
    #include <iostream>
    using namespace std;
    
    //Hash function you provided must be correspond to the type of the Key
    class HashFunc
    {
    public:
        int operator()(const string & key )
        {
            int hash = 0;
            for(int i = 0; i < key.length(); ++i)
            {
                hash = hash << 7 ^ key[i];
            }
            return (hash & 0x7FFFFFFF);
        }
    };
    
    //Equal function you provided to check whether two Keys are equal
    //must be correspond to the type of the Key
    class EqualKey
    {
    public:
        bool operator()(const string & A ,const string & B)
        {
            if(A.compare(B) == 0)
                return true;    //if equal return true
            else
                return false;    //else false
        }
    };
    
    int main()
    {
        HashMap<string,string,HashFunc,EqualKey> hm;
    
        hm.insert("hello" , "you");
        hm.insert("why" , "dream");
        hm.insert("java" ,"good");
        hm.insert("welcome" ,"haha");
    
        hm.insert("welcome" ,"hehe"); //error, key-value must be unique
    
    
        cout<<"after insert:"<<endl;
        cout<<hm.find("welcome")<<endl;
        cout<<hm.find("java")<<endl;
        cout<<hm["why"]<<endl;
        cout<<hm["hello"]<<endl;
    
        if(hm.remove("hello"))
            cout<<"remove is ok"<<endl;    //remove is ok
        cout<<hm.find("hello")<<endl; //not exist print NULL
    
        hm["why"] = "love"; //modify the value 
        cout<<hm["why"]<<endl;
    
        return 0;
    }
  • 相关阅读:
    mysql常用函数
    mysql中utf8_bin、utf8_general_ci、utf8_general_cs编码区别
    JS 中的return false的作用
    css3 animation动画执行结束,停顿几秒后重新开始执行
    (原)人月神话-阅读笔记
    (原创)cocosStudio: text设置颜色问题
    (原创)cocos-js js调用android
    (原创)cocos-js 实现震屏效果
    (转)Cocos2d-js中使用Shader方法--以一个简单的波纹效果为例:
    (转)Cocos2dx-JS 在 Sprite 上使用 Shader
  • 原文地址:https://www.cnblogs.com/luxiaoxun/p/2667782.html
Copyright © 2011-2022 走看看