码迷,mamicode.com
首页 > 其他好文 > 详细

哈希桶

时间:2016-04-10 19:35:01      阅读:325      评论:0      收藏:0      [点我收藏+]

标签:哈希桶

头文件:
//  1.用   《负载因子》   来减少哈希冲突                                                 **
//  2.用开辟  《素数》  个空间来减少哈希冲突                                             **
//  3.用 《线性探测》·《二次探测》·《string的特殊算法》   来减少哈希冲突               **
//  4.防止   《数据冗余》
//  5.用头插法插入节点》》》》》》为什么?
//  6.用  《伪函数》 实现功能模块的 复用     还有  《模板特化》  使功能更直观                                                
//  7.用  《c_str()》   把  string 转化为 char*                                          **
//  8.用特殊的函数   《string 的哈希函数》
//  9.一个数用  《 &0x7FFFFFFF  》  能保证为正数
//  10.注意  size_t类型进行   --  运算时的  零值


//****************              总结       ****************************************
//哈希表是用一个哈希函数是一个key只对应一个value  相当于 Y = F(X)  使哈希表的查找的
//的时间复杂度为0(1)。构造哈希表的方法有直接定址法----就是哈希函数为线性函数,如:
//y = x 或者 y = x + 1 之类的 还有除留余数法  哈希函数为 y = x % capacity等
//构造哈希表的关键是减少哈希冲突,主要方法分为  闭散列法:线性探测 和 二次探测
// 开链法:哈希桶   还有可以减少哈希冲突的细节有:设置负载因子,容量用素数,使用特制
//的string 转化为 数字的方法
//构造哈希表时要防止数据冗余
//**********************************************************************************



#ifndef HASHBACKET_HPP
#define HASHBACKET_HPP
#include<iostream>
#include<vector>
#include<string>
using namespace std;

template<class K, class V>
struct KeyValue
{
    K _key;
    V _value;
    KeyValue<K, V>* _next;

    KeyValue()
    {}

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

template<class K>
struct HashFuncDefault
{
    size_t operator()(const K& key)
    {
        return key;
    }
};

static size_t BKDRHash(const char* str)    //实现 string 类型 转化为 整数
{
    unsigned int seed = 131;
    unsigned int hash = 0;
    while (*str)
    {
        hash = hash * seed + (*str++);
    }
    return (hash & 0x7FFFFFFF);                //   保证返回的是正数   *********  《《技巧》》
}

template<>
struct HashFuncDefault<string>   //特化HashFuncDefault
{
    size_t operator()(const string& key)
    {
        return  BKDRHash(key.c_str());    //要用c_str()才能把string 转化为 char*
    }
};

#endif



定义文件:


#pragma once
#include"HashBucket.hpp"


template<class K, class V, class HF = HashFuncDefault<K>>
class HashBacket
{
public:
    HashBacket()
        :_size(0)                              
    {}

    ~HashBacket()                         //vector 会调自己的析构函数
    {
        _size = 0;  
    }

    bool Insert(const K& key,const V& value)                      
    {
        _CheckCapacity();

        int index = HashFunc(key,_table.size());

        KeyValue<K, V>* cur = _table[index];
        while (cur != NULL)
        {
            if (cur->_key != key)    //防止key冗余  而不能用防止value 冗余
            {
                cur = cur->_next;
            }
            else
            {
                return false;
            }
        }

        KeyValue<K, V>* tem = new KeyValue<K, V>(key, value);   //用头插法插入节点
        tem->_next = _table[index];
        _table[index] = tem;

        _size++;    
    }

    KeyValue<K, V>* Find(const K& key)        // 时间复杂度为    O(1)
    {
        size_t index = HashFunc(key,_table.size());

        KeyValue<K, V>* cur = _table[index];
        while (cur != NULL)
        {
            if (cur->_key == key)
            {
                return cur;
            }
            cur = cur->_next;
        }

        return NULL;
    }

    bool Remove(const K& key)
    {
        size_t index = HashFunc(key, _table.size());

        KeyValue<K, V>* cur = _table[index];
        KeyValue<K, V>* prev = cur;

        if (cur == NULL)
        {
            return false;
        }
        while (cur != NULL)
        {
            if (cur->_key == key)
            {
                prev = cur->_next;
                delete cur;
                _size--;
                return true;
            }
            cur = cur->_next;
            prev = cur;
        }

        return false;

    }

    void Print()
    {
        for (size_t i = 0; i < _table.size(); i++)
        {
            KeyValue<K, V>* cur = _table[i];
            
            if (cur == NULL)
            {
                cout << i << ":" << "[" << NULL << "]" << endl;
            }
            while (cur != NULL)
            {
                //printf("%d : [%d]", cur->_key, cur->_value);
                cout << cur->_key << ":" << "[" << cur->_value << "]" << endl;
                cur = cur->_next;
            }
        }
    }

protected:
    void _CheckCapacity()
    {
        if (_table.size() == _size)    //表内所有空间已用完时  也就是负载度为一时
        {
            size_t newCapacity = _GetPrimenNumber(_table.size());
            vector<KeyValue<K, V>*> tem;
            tem.resize(newCapacity);         //使tem的可使用空间为newCapacity

            for (size_t i = 0; i < _table.size(); i++)   //搬数据
            {
                KeyValue<K, V>* cur = _table[i];
                while (cur != NULL)
                {
                    KeyValue<K, V>* move = cur;
                    cur = cur->_next;

                    size_t index = HashFunc(move->_key,tem.size());
                    move->_next = tem[index];            //用头插法更方便
                    tem[index] = move;
                }
            }
            _table.swap(tem);     //深拷贝的现代写法
        }
    }

    int HashFunc(const K& key,size_t capacity)
    {
        HF hashFunc;                          //创建一个HF的对象  
        return hashFunc(key) % capacity;      //会去调具体的对象的operator()

        //return key % capacity;
    }

    unsigned long _GetPrimenNumber(const size_t capacity)   //取素数   用来减少冲突  
    {
        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
        };

        size_t i = 0;
        while (capacity >= _PrimeList[i] && i <= _PrimeSize)  
        {
            i++;
        }

        return _PrimeList[i];
    }

protected:
    vector<KeyValue<K, V>*> _table;     //_table.size()表示容量
    size_t _size;                       //表示个数
};


void Test1()
{
    HashBacket<int, int> h1;
    h1.Insert(1, 1);
    h1.Insert(2, 2);
    h1.Insert(3, 3);
    h1.Insert(4, 4);
    h1.Insert(5, 5);
    h1.Remove(5);
    h1.Print();
    
    HashBacket<string, string> h2;
    h2.Insert("你好", "hello");
    h2.Insert("改变", "change");
    h2.Insert("世界", "world");
    h2.Print();
    KeyValue<string,string>* cur =  h2.Find("世界");
    cout << cur->_key << ":" << "[" << cur->_value << "]" << endl;

    
}

int main()
{
    Test1();
    return 0;
}




技术分享

技术分享

本文出自 “水仙花” 博客,请务必保留此出处http://10704527.blog.51cto.com/10694527/1762371

哈希桶

标签:哈希桶

原文地址:http://10704527.blog.51cto.com/10694527/1762371

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!