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;
}

 

 

作者:阿凡卢

出处:http://www.cnblogs.com/luxiaoxun/

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

http://www.cnblogs.com/luxiaoxun/archive/2012/09/02/2667782.html

时间: 2024-11-05 16:36:57

hashmap的C++实现的相关文章

java-jquery解析xml怎样把结果存到list或者hashmap最后生成excel表格

问题描述 jquery解析xml怎样把结果存到list或者hashmap最后生成excel表格 $.ajax({ type:""GET"" dataType:""XML"" timeout: 1000 //设定超时 cache: false //禁用缓存 url:""${pageContext.request.contextPath}/xml/from.xml"" success:fun

不正当使用HashMap导致cpu 100%的问题追究

因最近hashmap误用引起的死循环又发生了一些案例,左耳朵浩子写了一篇blog 疫苗:Java HashMap的死循环,看了一下,大家的分析如出一辙.这篇blog也是好几年前写的了,之前在平台技术部的博客上贴过,随着组织结构的调整,那个博客可能不再维护,把这篇文章在这儿也保存一下. 李鹏同学在blog里写了篇关于HashMap死锁模拟的文章: http://blog.csdn.net/madding/archive/2010/08/25/5838477.aspx 做个纠正,那个不是死锁问题,而

[Java] TreeMap、HashMap、LindedHashMap的区别

版权声明:请尊重个人劳动成果,转载注明出处,谢谢! Map家族的继承关系 1 . TreeMap TreeMap实现SortMap接口,能够把它保存的记录根据键排序, 默认是按键值的升序排序(自然顺序),也可以指定排序的比较器( Comparator ),当用Iterator 遍历TreeMap时,得到的记录是排过序的. 注意,此实现不是同步的.如果多个线程同时访问一个映射,则其必须 外部同步.这一般是通过对自然封装该映射的对象执行同步操作来完成的.如果不存在这样的对象,则应该使用 Collec

javascript hashmap:HashMap的JavaScript实现

function hashMap(){/*** Map大小*/var size = 0;/*** 容器默认最大长度*/var length = 256var loadfactor = 0.75;/*** 质数*/var prime = 1000000;/*** 对象*/var table = new Array(length);/*** 设置构建Hash质数* @param {Object} p*/this.setPrime = function(p){this.prime = p;}/***

Java中对HashMap的深度分析

在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键.由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题.找遍了大大小小的论坛,也把<Java 虚拟机规范>,<apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector>,和<Thinking in Java>翻了也找不到很好的答案,于是一气之下把JDK的 src 解压出来研究,扩然开朗,遂写此文,跟大家分享感

Java的数组(Array)、Vector、ArrayList、HashMap的异同

数组   array(数组)和Vector是十分相似的Java构件(constructs),两者全然不同,在选择使用时应根据各自的功能来确定. 1.数组:Java arrays的元素个数不能下标越界,从很大程度上保证了Java程序的安全性,而其他一些语言出现这一问题时常导致灾难性的后果.        Array可以存放Object和基本数据类型,但创建时必须指定数组的大小,并不能再改变.值得注意的是:当Array中的某一元素存放的是Objrct reference 时,Java不会调用默认的构

Java中对HashMap的深度分析与比较

比较 在Java的世界里,无论类还是各种数据,其结构的处理是整个程序的逻辑以及性能的关键.由于本人接触了一个有关性能与逻辑同时并存的问题,于是就开始研究这方面的问题.找遍了大大小小的论坛,也把<Java 虚拟机规范>,<apress,.java.collections.(2001),.bm.ocr.6.0.shareconnector>,和<Thinking in Java>翻了也找不到很好的答案,于是一气之下把JDK的 src 解压出来研究,扩然开朗,遂写此文,跟大家

一个简单的HashMap C语言实现

用C语言实现一个简单实用的hashmap,具有一定的实际意义.尤其我们不想使用STL里面的map<...>类的时候.我实现的这个hashmap,用来做key---value的映射,key必须是有效的字符串,value是调用者分配的任意类型的数据.这个hashmap适合在一些简单的场合下,消耗极少的资源. 首先定义头文件如下: /* * hashmap.h * Generic hash map: key(string)-value(any type). * cheungmine * Sep. 2

Java集合源码剖析:HashMap源码剖析

HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap. HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆. HashMap源码剖析 HashMap的源码如下(加入了比较详细的注释): pac

Java集合学习(十) HashMap详细介绍(源码解析)和使用示例

这一章,我们对HashMap进行学习. 我们先对HashMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用HashMap. 第1部分 HashMap介绍 HashMap简介 HashMap 是一个散列表,它存储的内容是键值对(key-value)映射. HashMap 继承于AbstractMap,实现了Map.Cloneable.java.io.Serializable接口. HashMap 的实现不是同步的,这意味着它不是线程安全的.它的key.value都可以为null.此外