哈希桶的实现

#pragma once
#include<vector>

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

template<>
struct __HashFunc<string>   //特化
{
    static size_t BKDRHash(const char*str)    //BKDRHash算法
    {

unsigned int seed = 131;// 31 131 1313 13131 131313
        unsigned int hash= 0;
        while (*str)
        {
            hash = hash*seed + (*str++);
        }
        return(hash & 0x7FFFFFFF);
    }

size_t operator()(const string& str)
    {
        return BKDRHash(str.c_str());
    }
};

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

KVNode(const K& key, const V& value)
        :_key(key)
        , _value(value)
        , _next(NULL)
    {}
};
template<class K, class V, template<class> class HashFunc = __HashFunc>
class Hash
{
public:
      typedef KVNode<K, V> Node;
    Hash()     //构造函数
        :_size(0)
    {}

~Hash()     //析构函数
    {
        Clear();
    }

Hash(const Hash& ht)    //拷贝构造函数
    {
        Copy(ht);
    }

Hash& operator=(const Hash&ht)      //赋值运算符的重载
    {
        if (this != &ht)
        {
            Clear;
            Copy(ht);
        }
        return *this;
    }

bool Insert(const K& key,const V& value)   //插入节点
    {
        _CheckSize();     //检查容量,看是否需要扩容
        size_t index = _HashFunc(key,_tables.size());
        if (Find(key))       //如果有这个值则说明不需要插入
            return false;
       
        //单链表的头插
        Node* head = _tables[index];
        Node* tmp = new Node(key, value);
        tmp->_next =head;
        _tables[index] = tmp;
        ++_size;
        return true;
    }

//bool Insert(const K& key, const V&value)
    //{
    //    _CheckSize();
    //    size_t index = _HashFunc(key, _tables.size());
    //    Node*begin = _tables[index];
    //    while (begin)
    //    {
    //        if (begin->_key== key)
    //        {
    //            return false;
    //        }
    //        begin = begin->_next;
    //    }
    //    Node* head = _tables[index];
    //    Node* tmp = new Node(key, value);   //头插
    //    tmp->_next = head;
        /*_tables[index] = tmp;
        ++_size;
        return true;
    }*/

/*bool Remove(const K& key)
    {
        size_t index = _HashFunc(key,_tables.size());
        Node* cur = _tables[index];
        Node* prev = NULL;
        while (cur)
        {
            if (cur->_key == key)
            {
                if (prev == NULL)
                    _tables[index] = cur->_next;
                else
                    prev->_next = cur->_next;
            
                delete cur;
                --_size;
                return true;
            }    
            prev = cur;
            cur = cur->_next;
        }
        return false;
    }*/

bool Remove(const K& key)    //删除节点的函数
    {
        size_t index = _HashFunc(key, _tables.size());
        Node* cur = _tables[index];
        if (cur == NULL)
            return false;

if (cur->_key == key)   //key为桶的头结点
        {
            _tables[index] = cur->_next;
            delete cur;
            --_size;
            return true;
        }

Node* prev = cur;  //key为桶的中间节点
        cur = cur->_next;
        while (cur)
        {
            if (cur->_key == key)
            {
                prev->_next = cur->_next;
                delete cur;
                --_size;
                return true;
            }
            prev = prev;
            cur = cur->_next;
        }
        return false;
    }

Node* Find(const K& key)    //查找节点
    {
        size_t index = _HashFunc(key,_tables.size());
        Node* cur = _tables[index];
        while (cur)
        {
            if (cur->_key == key)
                return cur;
            cur = cur->_next;
        }
        return NULL;
    }

void Print()    //打印哈希桶
    {
        cout << "capacity" << "    " << "size" << ":" << _tables.size() << "   " << _size << endl;
        for (size_t i = 0; i < _tables.size(); ++i)
        {
            Node* cur = _tables[i];
            if (cur == NULL)
            {
                continue;
            }
            //cout << "[" << i << "]" << "    ";
            printf("【%d】", i);
            while (cur)
            {
                cout << "{" << cur->_key << "," << cur->_value << "}->";
                cur = cur->_next;
            }
            cout << "NULL" << endl;
        }
    }
//protected:
    void _CheckSize()     //检查容量,如果需要扩容就进行扩容
    {
        if (_size == 0 || _size == _tables.size())   
        {
            size_t capacity = _GetnextPrime(_size);
            vector<Node*> Hashtable;
            Hashtable.reserve(capacity);
            Hashtable.assign(capacity, 0);
            for (size_t i = 0; i < _tables.size(); ++i)
            {
                Node* begin = _tables[i];
                while (begin)
                {
                    Node* tmp = begin;
                    begin = begin->_next;

size_t index = _HashFunc(tmp->_key,capacity);

Node* head = Hashtable[index];
                    tmp->_next = head;
                    Hashtable[index] = tmp;
                }
            }
            _tables.swap(Hashtable);
        }
    }

size_t _GetnextPrime(size_t num)
    {
        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
        };

for (size_t i = 0; i < _Primesize; ++i)
        {
            if (_PrimeList[i]>num)
            {
                return _PrimeList[i];
            }
            return _PrimeList[_Primesize - 1];
        }
    }

size_t _HashFunc(const K& key,size_t capacity)
    {
        return HashFunc<K>()(key) %capacity;
    }

void Clear()   //素组中的元素是指针,因此要特别注意先释放每个节点下的单链表,否则造成内存泄漏
    {
        for (size_t i = 0; i < _tables.size(); ++i)
        {
            Node* cur = _tables[i];
            while (cur)
            {
                Node* del = cur;
                cur = cur->_next;
                delete del;
            }
            _tables[i] = NULL;
        }
    }

void Copy(const Hash& ht)     //拷贝函数
    {
        _tables.resize(ht._tables.size());
        for (size_t i = 0; i < _tables.size(); ++i)
        {
            Node* cur = ht._tables[i];
            while (cur)
            {
                Node* newCur = new Node(cur->_key, cur->_value);
                newCur->_next = _tables[i];
                _tables[i] = newCur;
                cur = cur->_next;
            }
        }
    }
protected:
    vector<Node*> _tables;
    size_t _size;
};

时间: 2024-10-27 21:57:48

哈希桶的实现的相关文章

openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)

这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题. 引用下前篇blog中分析讨论得到的flex_array结构体成员变量的含义结论: struct { int element_size; // 这是flex_array_part结构体存放的哈希头指针的大小 int total_nr_elements; // 这是全部flex_array_part结构体中的哈希头指针的总个数 int e

【数据结构】处理哈希冲突的开链法(哈希桶)算法实现

实现哈希表时,我们常见的方法是线性探测.二次探测,这两个算法也很简单.若有兴趣,可以查看我的博客.但是,这两个算法有一个共同点就是:空间利用率低.为什么这么说呢?线性探测.二次探测的高效性很大程度上要取决于它的载荷因子,载荷因子即:存放关键字个数/空间大小. 通过查阅资料,我发现,使用素数做除数可以减少哈希冲突(具体原因不详,大师专研的,发现很好用,就在这里分享给大家).见下: ----素数表 // 使用素数表对齐做哈希表的容量,降低哈希冲突 const int _PrimeSize = 28;

哈希桶

哈希桶:哈希桶就是盛放不同key链表的容器(即是哈希表),在这里我们可以把每个        key的位置看作是一个孔,孔里放了一个链表.或是使用一个顺序表来存放具        有相同哈希值的key的链表的头节点,利用这个头节点可以找到其它key值.

【干货】C++哈希桶(开链法解决哈希冲突)类的实现

开链法(哈希桶)是解决哈希冲突的常用手法,结构如下: 数据结构的设计思路是这样的,定义一个K-V的链式节点(Node),以数组方式存储节点指针 实现代码如下: #include<vector> #include"HashTable.h" size_t GetSize() { static size_t index = 0; const int _PrimeSize = 28; static const unsigned long _PrimeList[_PrimeSize]

哈希算法(一次探测,二次探测,哈希桶法)支持字典查询

HashTable-散列表/哈希表,是根据关键字(key)而直接访问在内存存储位置的数据结构.它通过一个关键值的函数将所需的数据映射到表中的位置来访问数据,这个映射函数叫做散列函数,存放记录的数组叫做散列表. 构造哈希表的几种方法 直接定址法--取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A.B为常数. 除留余数法--取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址.Hash(Key)= Key % P. 平方取中法

C++ 哈希表 线性探测 二次探测 哈希桶

#pragma once #include<iostream>//含一次探测  二次探测 #include<vector> #include<math.h> using namespace std; enum Status { EXIST, EMPTY, DELET, }; template <class K,class V> //key/value形式结构体 struct KV { K _key; V _value; KV(const K& key

哈希桶处理哈希冲突

哈希桶:哈希桶就是盛放不同key链表的容器(即是哈希表),我们可以把每个key的位置看作是一个指针,该指针所指向的位置里放了一个链表,可以认为是指针数组,故该方法也叫开链式. 相比闭散列,哈希桶提高了空间利用率:在实现哈希表时,常见的方法是线性探测.二次探测,这两个算法的具体实现可以查看我的博客.但是这两个算法有一个共同点就是:空间利用率低.为什么这么说呢?线性探测.二次探测的高效性很大程度上要取决于它的载荷因子,载荷因子即:存放关键字个数 / 空间大小. 通过查阅资料,我发现,使用素数做除数可

C++实现哈希桶

#pragma once #include <vector> #include <string> template<class K, class V> struct HashTableNode { K _key; V _value; HashTableNode<K, V>* _next; HashTableNode(const K& key, const V& value) :_key(key) ,_value(value) ,_next(N

Linux内核哈希表中的bucket桶

哈希表 哈希表(Hashtable)又称为“散列”,Hashtable是会根据索引键的哈希程序代码组织成的索引键(Key)和值(Value)配对的集合.Hashtable 对象是由包含集合中元素的哈希桶(Bucket)所组成的.而Bucket是Hashtable内元素的虚拟子群组,可以让大部分集合中的搜寻和获取工作更容易.更快速. 哈希函数(Hash Function)为根据索引键来返回数值哈希程序代码的算法.索引键(Key)是被存储对象的某些属性值(Value).当对象加入至 Hashtabl