hash表C++实现

来源:互联网 发布:o2o软件测试计划 编辑:程序博客网 时间:2024/06/11 10:06
仿照SGI扩展中的hash_set和hash_map实现了下面两个简化的模板类。
她们的使用方法与stl中的容器类相似,支持插入,查找,删除,遍历等。
成员函数名称和语义基本与stl中的容器类一致。
迭代器的使用也与stl容器类的基本一致。

main.cpp中的代码是个简单的测试用例,我写的有点乱。

编译:g++ -g -W -Wall -Wextra -o mytest main.cpp
执行:./mytest

main.cpp:
==============================================
// 2012年 02月 13日 星期一 14:15:42 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T

#include <iostream>
#include <cstdio>
#include <cstdlib>

#include <unistd.h>

#include "shuheng_hash.h"


using namespace std;


void tst_hash();
void tst_hash1();

class hash {
public:
    inline size_t operator ()(int k)
    {
        return k;
    }
};


int main()
{
    tst_hash();
    tst_hash1();
    return 0;
}

void tst_hash()
{
    shuheng::hash_map<int, int, hash> myhash(7);
    for(int i = 0; i < 65; ++i)
        myhash.insert(make_pair(i, i));

    cout << myhash.size() << endl;
    sleep(1);

    for(shuheng::hash_map<int, int, hash>::const_iterator p
            = myhash.begin(); p != myhash.end(); ++p)
        cout << p->first << "\t" << p->second << endl;
    cout << "====================================\n";
    sleep(1);

    for(shuheng::hash_map<int, int, hash>::iterator p
            = myhash.begin(); p != myhash.end(); ++p)
        p->second *= 2;

    for(shuheng::hash_map<int, int, hash>::const_iterator p
            = myhash.begin(); p != myhash.end(); ++p)
        cout << p->first << "\t" << p->second << endl;
    cout << "====================================\n";
    sleep(1);

    shuheng::hash_map<int, int, hash>::iterator pos;
    if((pos = myhash.find(38)) != myhash.end())
        myhash.erase(pos);

    for(shuheng::hash_map<int, int, hash>::const_iterator p
            = myhash.begin(); p != myhash.end(); ++p)
        cout << p->first << "\t" << p->second << endl;
    cout << "====================================\n";
    cout << myhash.size() << endl;
    sleep(1);

    for(shuheng::hash_map<int, int, hash>::iterator p
            = myhash.begin(); p != myhash.end(); ++p)
        myhash.erase(p);

    cout << myhash.size() << endl;

    for(int i = 0; i < 88; ++i)
        myhash.insert(make_pair(i, i * 3));
    for(shuheng::hash_map<int, int, hash>::const_iterator p
            = myhash.begin(); p != myhash.end(); ++p)
        cout << p->first << "\t" << p->second << endl;
    cout << "====================================\n";
    sleep(1);

    myhash.clear();

    shuheng::hash_map<int, int, hash> myhash1;
    for(int i = 0; i < 17; ++i)
        myhash1.insert(make_pair(i, i));

    shuheng::hash_map<int, int, hash>::iterator p;
    int i = 0;
    for(p = myhash1.begin(); i < 16; ++p, ++i)
        cout << p->first << "\t" << p->second << endl;
    cout << "====================================\n";
    sleep(1);

    for(shuheng::hash_map<int, int, hash>::const_iterator pos = p; pos != myhash1.end(); --pos)
        cout << pos->first << "\t" << pos->second << endl;
    cout << "====================================\n";
    sleep(1);

    for(shuheng::hash_map<int, int, hash>::const_iterator p
            = myhash1.begin(); p != myhash1.end(); p++)
        cout << p->first << "\t" << p->second << endl;
    cout << "====================================\n";
    sleep(1);

    i = 0;
    for(p = myhash1.begin(); i < 16; p++, ++i)
        cout << p->first << "\t" << p->second << endl;
    cout << "====================================\n";
    sleep(1);

    for(shuheng::hash_map<int, int, hash>::const_iterator pos = p; pos != myhash1.end(); pos--)
        cout << pos->first << "\t" << pos->second << endl;
    cout << "====================================\n";
    sleep(1);

    if((p = myhash1.find(3)) != myhash1.end()) {
        myhash1.erase(p++);
        myhash1.erase(p--);
    }
    for(shuheng::hash_map<int, int, hash>::const_iterator pos = myhash1.begin(); pos != myhash1.end(); ++pos)
        cout << pos->first << "\t" << pos->second << endl;
    cout << "====================================\n";
}

class hash_fun {
public:
    size_t operator ()(char *buf) const
    {
        size_t h = 0;
        unsigned char *p = (unsigned char *)buf;
        for(int i = 0; *p; ++i, ++p)
            h += *p * 37 * i;
        return h;
    }
};

class hash_cmp {
public:
    bool operator ()(const char *p1, const char *p2) const
    {
        return strcmp(p1, p2) == 0;
    }
};

void tst_hash1()
{
    shuheng::hash_set<char *, hash_fun, hash_cmp> myhash;
    FILE *fp;
    if((fp = fopen("./main.cpp", "r"))) {
        char buf[2048];
        while(fgets(buf, sizeof(buf), fp)) {
            int len = strlen(buf);
            if(len < 2) continue;
            char *p = new char [len];
            strncpy(p, buf, len - 1);
            p[len-1] = 0;

            pair<shuheng::hash_set<char *, hash_fun,
                hash_cmp>::iterator, bool> ret
                = myhash.insert(p);
            if(!ret.second)
                delete [] p;
        }
        fclose(fp);
    }
    for(shuheng::hash_set<char *, hash_fun, hash_cmp>::iterator p
            = myhash.begin(); p != myhash.end();
            ++p)
        cout << *p << endl;

    if((fp = fopen("./main.cpp", "r"))) {
        char buf[2048];
        while(fgets(buf, sizeof(buf), fp)) {
            int len = strlen(buf);
            if(len < 2) continue;
            buf[len-1] = 0;

            shuheng::hash_set<char *,
                hash_fun, hash_cmp>::iterator p;
            if((p = myhash.find(buf)) == myhash.end())
                cout << "can't find!" << endl;
        }
        fclose(fp);
    }
    for(shuheng::hash_set<char *, hash_fun, hash_cmp>::iterator p
            = myhash.begin(); p != myhash.end();
            ++p)
        delete [] *p;

    myhash.clear();
}
=============================================

shuheng_hash.h:
=============================================
// 2012年 02月 09日 星期四 08:49:48 CST
// author: 李小丹(Li Shao Dan) 字 殊恒(shuheng)
// K.I.S.S
// S.P.O.T


#ifndef SHUHENG_HASH_H
#define SHUHENG_HASH_H


#include <utility>
#include <functional>

#include <cstring>
#include <cassert>


using std::pair;


#define DEFAULT_HASH_SIZE 1021


namespace shuheng {

//==================hash_map=====================

//template: Key, Value, hash Function, Compare

template <class K, class V, class F, class C>
class hash_map;

template <class K, class V, class F, class C>
class map_iterator;

template <class K, class V, class F, class C>
inline static bool operator ==(
const map_iterator<K, V, F, C> &,
const map_iterator<K, V, F, C> &);

template <class K, class V, class F, class C>
inline static bool operator !=(
const map_iterator<K, V, F, C> &,
const map_iterator<K, V, F, C> &);


template <class K, class V, class F, class C>
class map_node {
public:
    friend class hash_map<K, V, F, C>;
    friend class map_iterator<K, V, F, C>;

private:
    map_node(const pair<K, V> &);

private:
    pair<const K, V> key_value;

    map_node *slot_next;
    map_node *slot_prev;
    map_node *list_next;
    map_node *list_prev;
};

template <class K, class V, class F, class C>
map_node<K, V, F, C>::map_node(const pair<K, V> &kv)
:key_value(kv), slot_next(0),
slot_prev(0), list_next(0), list_prev(0)
{
}


template <class K, class V, class F, class C>
class map_iterator {
public:
    friend class hash_map<K, V, F, C>;

    friend bool operator ==<K, V, F, C>(
    const map_iterator<K, V, F, C> &,
    const map_iterator<K, V, F, C> &);

    friend bool operator !=<K, V, F, C>(
    const map_iterator<K, V, F, C> &,
    const map_iterator<K, V, F, C> &);

public:
    map_iterator();
    map_iterator(const map_iterator &);

    /*map_iterator &operator =(const map_iterator &);
    const map_iterator &operator =(const map_iterator &) const;*/

    inline const map_iterator &operator ++() const;
    inline const map_iterator &operator --() const;
    inline map_iterator &operator ++();
    inline map_iterator &operator --();

    inline const map_iterator operator ++(int) const;
    inline const map_iterator operator --(int) const;
    inline map_iterator operator ++(int);
    inline map_iterator operator --(int);

    inline pair<const K, V> *operator ->();
    inline const pair<const K, V> *operator ->() const;

    inline const K &operator *() const;

private:
    map_iterator(map_node<K, V, F, C> *);

private:
    mutable map_node<K, V, F, C> *current;
};

template <class K, class V, class F, class C>
map_iterator<K, V, F, C>::map_iterator(map_node<K, V, F, C> *node)
:current(node)
{
}

template <class K, class V, class F, class C>
map_iterator<K, V, F, C>::map_iterator(const map_iterator<K, V, F, C> &s)
:current(s.current)
{
}

/*template <class K, class V, class F, class C>
map_iterator<K, V, F, C> &
map_iterator<K, V, F, C>::operator =(const map_iterator &s)
{
    current = s.current;
    return *this;
}

template <class K, class V, class F, class C>
const map_iterator<K, V, F, C> &
map_iterator<K, V, F, C>::operator =(const map_iterator &s) const
{
    current = s.current;
    return *this;
}*/

template <class K, class V, class F, class C>
map_iterator<K, V, F, C>::map_iterator()
:current(0)
{
}

template <class K, class V, class F, class C>
inline map_iterator<K, V, F, C> &
map_iterator<K, V, F, C>::operator ++()
{
    current = current->list_next;
    return *this;
}

template <class K, class V, class F, class C>
inline map_iterator<K, V, F, C> &
map_iterator<K, V, F, C>::operator --()
{
    current = current->list_prev;
    return *this;
}

template <class K, class V, class F, class C>
inline const map_iterator<K, V, F, C> &
map_iterator<K, V, F, C>::operator ++() const
{
    current = current->list_next;
    return *this;
}

template <class K, class V, class F, class C>
inline const map_iterator<K, V, F, C> &
map_iterator<K, V, F, C>::operator --() const
{
    current = current->list_prev;
    return *this;
}

template <class K, class V, class F, class C>
inline map_iterator<K, V, F, C>
map_iterator<K, V, F, C>::operator ++(int)
{
    map_iterator<K, V, F, C> tmp(*this);
    current = current->list_next;
    return tmp;
}

template <class K, class V, class F, class C>
inline map_iterator<K, V, F, C>
map_iterator<K, V, F, C>::operator --(int)
{
    map_iterator<K, V, F, C> tmp(*this);
    current = current->list_prev;
    return tmp;
}

template <class K, class V, class F, class C>
inline const map_iterator<K, V, F, C>
map_iterator<K, V, F, C>::operator ++(int) const
{
    map_iterator<K, V, F, C> tmp(*this);
    current = current->list_next;
    return tmp;
}

template <class K, class V, class F, class C>
inline const map_iterator<K, V, F, C>
map_iterator<K, V, F, C>::operator --(int) const
{
    map_iterator<K, V, F, C> tmp(*this);
    current = current->list_prev;
    return tmp;
}

template <class K, class V, class F, class C>
inline pair<const K, V> *
map_iterator<K, V, F, C>::operator ->()
{
    return &current->key_value;
}

template <class K, class V, class F, class C>
inline const pair<const K, V> *
map_iterator<K, V, F, C>::operator ->() const
{
    return &current->key_value;
}

template <class K, class V, class F, class C>
inline const K &map_iterator<K, V, F, C>::operator *() const
{
    return current->key_value.first;
}

template <class K, class V, class F, class C>
inline static bool operator ==(
    const map_iterator<K, V, F, C> &a,
    const map_iterator<K, V, F, C> &b)
{
    return a.current == b.current;
}

template <class K, class V, class F, class C>
inline static bool operator !=(
    const map_iterator<K, V, F, C> &a,
    const map_iterator<K, V, F, C> &b)
{
    return a.current != b.current;
}



template <class K, class V, class F,
     class C = std::equal_to<K> >
class hash_map {
public:
    typedef map_iterator<K, V, F, C> iterator;
    typedef const map_iterator<K, V, F, C> const_iterator;

public:
    hash_map();
    explicit hash_map(size_t);
    ~hash_map();

public:
    inline size_t size() const;
    inline const_iterator begin() const;
    inline const_iterator end() const;
    inline iterator begin();
    inline iterator end();
    pair<map_iterator<K, V, F, C>, bool>
        insert(const pair<K, V> &);
    inline map_iterator<K, V, F, C> find(const K &) const;
    void erase(const map_iterator<K, V, F, C> &);
    inline void clear();
private:
    hash_map(const hash_map &);
    hash_map &operator =(const hash_map &);

private:
    void destroy_slot(map_node<K, V, F, C> *);

    map_iterator<K, V, F, C>
    find_slot(map_node<K, V, F, C> *, const K &) const;

    void insert_hash(map_node<K, V, F, C> *, size_t);
    void insert_list(map_node<K, V, F, C> *);
    void erase_hash(map_node<K, V, F, C> *);
    void erase_list(map_node<K, V, F, C> *);

private:
    map_node<K, V, F, C> **hash_slot;
    map_node<K, V, F, C> *hash_list;
    size_t slot_count;
    size_t elmt_count;
};

template <class K, class V, class F, class C>
hash_map<K, V, F, C>::hash_map()
:hash_list(0), slot_count(DEFAULT_HASH_SIZE),
elmt_count(0)
{
    hash_slot = new map_node<K, V, F, C> *[DEFAULT_HASH_SIZE];
    assert(hash_slot);

    memset(hash_slot, 0, sizeof(void *) * DEFAULT_HASH_SIZE);
}

template <class K, class V, class F, class C>
hash_map<K, V, F, C>::hash_map(size_t hs)
:hash_list(0), slot_count(hs),
elmt_count(0)
{
    hash_slot = new map_node<K, V, F, C> *[hs];
    assert(hash_slot);

    memset(hash_slot, 0, sizeof(void *) * hs);
}

template <class K, class V, class F, class C>
hash_map<K, V, F, C>::~hash_map()
{
    destroy_slot(hash_list);
    delete [] hash_slot;
}

template <class K, class V, class F, class C>
void hash_map<K, V, F, C>::destroy_slot(map_node<K, V, F, C> *node)
{
    while(node) {
        map_node<K, V, F, C> *tmp = node;
        node = node->list_next;
        delete tmp;
    }
}

template <class K, class V, class F, class C>
inline size_t hash_map<K, V, F, C>::size() const
{
    return elmt_count;
}

template <class K, class V, class F, class C>
inline map_iterator<K, V, F, C>
hash_map<K, V, F, C>::find(const K &k) const
{
    F fun;
    size_t p = fun(k) % slot_count;

    return find_slot(hash_slot[p], k);
}

template <class K, class V, class F, class C>
map_iterator<K, V, F, C>
hash_map<K, V, F, C>::find_slot(
    map_node<K, V, F, C> *node, const K &k) const
{
    C cmp;
    while(node) {
        if(cmp(node->key_value.first, k))
            return map_iterator<K, V, F, C>(node);
        node = node->slot_next;
    }
    return map_iterator<K, V, F, C>(0);
}

template <class K, class V, class F, class C>
pair<map_iterator<K, V, F, C>, bool>
hash_map<K, V, F, C>::insert(const pair<K, V> &kv)
{
    F fun;
    size_t p = fun(kv.first) % slot_count;
    map_iterator<K, V, F, C> pos =
        find_slot(hash_slot[p], kv.first);
    bool ss = false;
    if(pos == map_iterator<K, V, F, C>(0)) {
        map_node<K, V, F, C> *node =
            new map_node<K, V, F, C>(kv);

        insert_hash(node, p);
        insert_list(node);

        ss = true;
        ++elmt_count;
    }
    return std::make_pair(pos, ss);
}

template <class K, class V, class F, class C>
void hash_map<K, V, F, C>::insert_hash(map_node<K, V, F, C> *node,
        size_t p)
{
    //node->slot_next = hash_slot[p];
    if(hash_slot[p]) {
        node->slot_next = hash_slot[p];
        hash_slot[p]->slot_prev = node;
    }
    hash_slot[p] = node;
}

template <class K, class V, class F, class C>
void hash_map<K, V, F, C>::insert_list(map_node<K, V, F, C> *node)
{
    //node->list_next = hash_list;
    if(hash_list) {
        node->list_next = hash_list;
        hash_list->list_prev = node;
    }
    hash_list = node;
}

template <class K, class V, class F, class C>
void hash_map<K, V, F, C>::erase(const map_iterator<K, V, F, C> &pos)
{
    map_node<K, V, F, C> *node = pos.current;

    erase_hash(node);
    erase_list(node);

    delete node;
    --elmt_count;
}

template <class K, class V, class F, class C>
void hash_map<K, V, F, C>::erase_hash(map_node<K, V, F, C> *node)
{
    if(node->slot_next)
        node->slot_next->slot_prev = node->slot_prev;

    if(node->slot_prev) {
        node->slot_prev->slot_next = node->slot_next;
    } else {
        F fun;
        size_t p = fun(node->key_value.first) % slot_count;
        hash_slot[p] = node->slot_next;
    }
}

template <class K, class V, class F, class C>
void hash_map<K, V, F, C>::erase_list(map_node<K, V, F, C> *node)
{
    if(node->list_next)
        node->list_next->list_prev = node->list_prev;

    if(node->list_prev)
        node->list_prev->list_next = node->list_next;
    else
        hash_list = node->list_next;
}

template <class K, class V, class F, class C>
inline map_iterator<K, V, F, C>
hash_map<K, V, F, C>::begin()
{
    return iterator(hash_list);
}

template <class K, class V, class F, class C>
inline map_iterator<K, V, F, C>
hash_map<K, V, F, C>::end()
{
    return iterator(0);
}

template <class K, class V, class F, class C>
inline const map_iterator<K, V, F, C>
hash_map<K, V, F, C>::begin() const
{
    return iterator(hash_list);
}

template <class K, class V, class F, class C>
inline const map_iterator<K, V, F, C>
hash_map<K, V, F, C>::end() const
{
    return iterator(0);
}

template <class K, class V, class F, class C>
inline void hash_map<K, V, F, C>::clear()
{
    destroy_slot(hash_list);

    elmt_count = 0;
    hash_list = 0;

    memset(hash_slot, 0, sizeof(void *) * slot_count);
}

//==================hash_set===============

// template: Key, hash Function, Compare
template <class K, class F,
     class C = std::equal_to<K> >
class hash_set : public hash_map<K, char, F, C> {
public:
    typedef map_iterator<K, char, F, C> iterator;
    typedef const map_iterator<K, char, F, C> const_iterator;

public:
    hash_set();
    explicit hash_set(size_t);

public:
    pair<map_iterator<K, char, F, C>, bool>
    insert(const K &);

private:
    hash_set(const hash_set &);
    hash_set &operator =(const hash_set &);
};

template <class K, class F, class C>
hash_set<K, F, C>::hash_set()
:hash_map<K, char, F, C>::hash_map()
{
}

template <class K, class F, class C>
hash_set<K, F, C>::hash_set(size_t s)
:hash_map<K, char, F, C>::hash_map(s)
{
}

template <class K, class F, class C>
pair<map_iterator<K, char, F, C>, bool>
hash_set<K, F, C>::insert(const K &k)
{
    return hash_map<K, char, F, C>::insert(std::make_pair(k, 0));
}


} // end of namespace

#endif
=============================================