标签:哈希桶
头文件:
// 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