哈希表的静态,动态,以及key/value形式

哈希是一种算法,将指定的数据按一定规律映射到一段空间内,又可以按照这种规律对它的值进行相应的操作,这一段空间可以称作哈希表,它的的查找速度要快于线性的数据结构,同时也快于表格队列等,所以它具有独特的优势,一般将哈希算法用于快速查找和加密算法。

对于最简单的哈希表,里面设置一个key,它决定将这个值存于哈希表的什么位置,同时把每个设置一个状态,如果有插入数据就将其设置为EXITS,其他操作同理,现在可以实现最简单的哈希表。

namespace First

{

enum State

{

EMPTY,

DELETE,

EXITS

};

template <typename T>

class HashTable

{

public:

HashTable(size_t capacity = 10)//构造

:_capacity(capacity)

, _tables(new T[_capacity])

, _states(new State[_capacity])

, _size(0)

{

for (int i = 0; i < _capacity; i++)//最初始得状态置成空的

{

_states[i] = EMPTY;

}

}

~HashTable()//析构

{

delete[] _tables;

delete[] _states;

}

HashTable(const HashTable<T>& h)//拷贝构造

:_capacity(h._capacity)

, _tables(new T[h._capacity])

, _states(new State[h._capacity])

, _size(h._size)

{

for (int i = 0; i < h._capacity; i++)

{

_tables[i] = h._tables[i];

_states[i] = h._states[i];

}

}

HashTable& operator=(HashTable<T> h)//赋值运算符重载

{

if (this != &h)

{

swap(_tables, h._tables);

swap(_states, h._states);

swap(_capacity, h._capacity);

swap(_size, h._size);

}

return *this;

}

bool Insert(const T& key)//插入

{

if (_size == _capacity)

{

cout << "HashTable full" << endl;

return false;

}

int index = HashFunc(key);

int start = index;

while (_states[index] == EXITS)//往后线形探测

{

if (_tables[index] == key)//有相等的

{

return false;

}

index++;

if (index == _capacity)//最后一个

{

index = 0;

}

if (index == start)//找了一圈没找到

{

return false;

}

}

_tables[index] = key;

_states[index] = EXITS;

_size++;

}

bool Find(const T& key)//查找

{

int index = HashFunc(key);

int start = index;

while (_states[index] != EMPTY)

{

if (_tables[index] == key)

{

if (_states[index] != DELETE)

{

cout << "find succees" << endl;

return true;

}

else

{

cout << "find fail" << endl;

return false;

}

}

index++;

if (index == _capacity)

{

index = 0;

}

if (start == index)

{

cout << "find fail" << endl;

return false;

}

}

cout << "find fail" << endl;

return false;

}

bool Remove(const T& key)///删除

{

int index = HashFunc(key);

int start = index;

while (_states[index] != EMPTY)

{

if (_tables[index] == key)

{

if (_states[index] != DELETE)

{

cout << "delete key" << endl;

_states[index] = DELETE;

return true;

}

else

{

cout << "delete fail" << endl;

return false;

}

}

index++;

if (index == _capacity)

{

index = 0;

}

if (start == index)

{

return false;

}

}

cout << "delete fail" << endl;

return true;

}

void Print()//打印哈希表

{

for (int i = 0; i < _capacity; i++)

{

cout << ‘[‘ << _tables[i] << ‘,‘ << _states[i] << ‘]‘ << ‘ ‘;

}

cout << endl;

}

protected:

int HashFunc(const T& key)

{

return key%_capacity;

}

private:

size_t _capacity;

T* _tables;

State* _states;

size_t _size;

};

}

/**************************************/

从上面的代码可以看出,这个哈希表并不适用于实际,因为首先它是一个静态的,如果存入的key值过多就会造成越界访问,同时用的是线性探测方法,这样降低了cpu的访问命中率,现在可以实现一种动态的而且随意设置负载因子的功能。

namespace Second//因为有负载因子的限制,可以提高cpu访问命中率

{

enum State

{

EMPTY,

DELETE,

EXITS

};

template <typename T>

class HashTable

{

public:

HashTable(size_t capacity = 30)//构造

:_capacity(capacity)

, _tables(new T[_capacity])

, _states(new State[_capacity])

, _size(0)

{

for (int i = 0; i < _capacity; i++)//最初始得状态置成空的

{

_states[i] = EMPTY;

}

}

~HashTable()//析构

{

delete[] _tables;

delete[] _states;

}

HashTable(const HashTable<T>& h)//拷贝构造

:_capacity(h._capacity)

, _tables(new T[h._capacity])

, _states(new State[h._capacity])

, _size(h._size)

{

for (int i = 0; i<h._capacity; i++)

{

_tables[i] = h._tables[i];

_states[i] = h._states[i];

}

}

HashTable& operator=(HashTable<T> h)//赋值运算符重载

{

if (this != &h)

{

swap(_tables, h._tables);

swap(_states, h._states);

swap(_capacity, h._capacity);

swap(_size, h._size);

}

return *this;

}

//bool Insert(const T& key)//插入(线性探测)

//{

//_CheckCapacity();

//int index = _HashFunc(key);

//int start = index;

//while (_states[index]==EXITS)

//{

//if (_tables[index] == key)

//{

//return false;

//}

//index++;

//if (index == _capacity)

//{

//index = 0;

//}

//if (index == start)

//{

//return false;

//}

//

//}

//_tables[index] = key;

//_states[index] = EXITS;

//_size++;

//}

bool Insert(const T& key)//插入(二次探测,即某个数的二次方,这样数据存着更稀疏)

{

_CheckCapacity();

int index = _HashFunc(key);

int start = index;

int i = 0;

while (_states[index]==EXITS)

{

if (_tables[index] == key)

{

return false;

}

index = _HashFuncT(index, ++i);

if (start = index)

{

return false;

}

if (index == _capacity)

{

index = 0;

}

}

_tables[index] = key;

_states[index] = EXITS;

_size++;

}

bool Find(const T& key)//查找

{

int index = _HashFunc(key);

int start = index;

int i = 0;

while (_states[index]!=EMPTY)

{

if (_tables[index] == key)

{

if (_states[index] != DELETE)

{

cout << "find success" << endl;

return true;

}

else

{

cout << "find fail" << endl;

return false;

}

}

index = _HashFuncT(index, ++i);

if (start = index)

{

cout << "find fail" << endl;

return false;

}

if (index == _capacity)

{

index = 0;

}

}

cout << "find fail" << endl;

return false;

}

bool Remove(const T& key)///删除

{

int index = _HashFunc(key);

int start = index;

int i = 0;

while (_states[index] == EXITS)

{

if (_tables[index] == key)

{

_states[index] = DELETE;

_size--;

return true;

}

index = _HashFuncT(index, ++i);

if (start == index)

{

return false;

}

if (index == _capacity)

{

index = 0;

}

}

return false;

}

void Print()//打印哈希表

{

for (int i = 0; i < _capacity; i++)

{

cout << ‘[‘ << _tables[i] << ‘,‘ << _states[i] << ‘]‘ << ‘ ‘;

}

cout << endl;

}

protected:

int _HashFuncT(int index,int i)

{

return (index + i*i) % _capacity;

}

int _HashFunc(const T& key)

{

return key%_capacity;

}

void _CheckCapacity()//检查容量

{

if ((10 * _size)/ _capacity == 6)//负载因子设为0.6

{

HashTable<T> tmp(2 * _capacity);

for (int i = 0; i < _capacity; i++)

{

if (_states[i]==EXITS)

{

tmp.Insert(_tables[i]);

}

}

_swap(tmp);

}

}

void _swap(HashTable<T> h)

{

swap(_tables, h._tables);

swap(_states, h._states);

swap(_capacity, h._capacity);

swap(_size, h._size);

}

private:

size_t _capacity;

T* _tables;

State* _states;

size_t _size;

};

}

/****************************************/

上面的代码对于key形式的相对第一种已经比较健全了。现在可以利用哈希算法可以实现一种key/value形式的功能,可以支持字典功能,key是一个信息,同时value是key的一个附带信息,比如说key为学号,那么班级就是附带的信息value,例如还有简单的英汉字典形式,现进行简单的实现。

namespace Third//支持字典形式的

{

enum State

{

EMPTY,

DELETE,

EXITS

};

template<class T,class V>

struct HashTableNode

{

HashTableNode()

{}

HashTableNode(const T& key, const V& value)

:_key(key)

, _value(value)

{}

T _key;

V _value;

};

template <class T>

struct __HashFunc

{

size_t operator()(const T& key)

{

return key;

}

};

//实现key,value形式,并且是二次探测的

template <class T ,class V,class HashFunc=__HashFunc<T>>

class Dictionary

{

public:

Dictionary(size_t capacity=10)

:_capacity(capacity)

, _tables(new HashTableNode<T,V> [_capacity])

, _states(new State[_capacity])

,_size(0)

{

for (int i = 0; i < _capacity; i++)

{

_states[i] = EMPTY;//将最开始的状态置为空

}

}

~Dictionary()

{

delete[] _tables;

delete[] _states;

}

bool Insert(const T& key,const V& value)

{

_CheckCapacity();

int index = _HashFunonce(key);

int start = index;

int i = 0;

while (_states[index] == EXITS)

{

if (_tables[index]._key == key)

{

return false;

}

index = _HashFuntwice(index, ++i);

if (index == _capacity)

{

index = 0;

}

if (index == start)

{

return false;

}

}

_tables[index] = HashTableNode<T, V>(key, value);

_states[index] = EXITS;

_size++;

return true;

}

HashTableNode<T,V>* Find(const T& key)

{

int index = _HashFunonce(key);

int start = index;

int i = 0;

while (_states[index]==EXITS)

{

if (_tables[index]._key == key)

{

cout << "find success" << endl;

return _tables+index;

}

index = _HashFuntwice(index, ++i);

if (start == index)

{

cout << "find fail" << endl;

return NULL;

}

}

cout << "find fail" << endl;

return NULL;

}

bool Remove(const T& key)

{

int index = _HashFunonce(key);

int start = index;

int i = 0;

while (_states[index]!=EMPTY)

{

if (_tables[index]._key == key)

{

if (_states[index]!=DELETE)

{

_states[index] = DELETE;

_size--;

return true;

}

else

{

return false;

}

}

index = _HashFuntwice(index, ++i);

if (index == start)

{

return false;

}

}

return false;

}

void Print()

{

for (int i = 0; i < _capacity; i++)

{

cout << "[" << _tables[i]._key << "," << _tables[i]._value <<","<< _states[i]<<"]" << " ";

}

cout << endl;

}

protected:

void _CheckCapacity()//将负载因子设为0.6

{

if (_size * 10 / _capacity == 6)

{

Dictionary<T, V, HashFunc> tmp(2 * _capacity);

for (int i = 0; i < _capacity; i++)

{

if (_states[i] == EXITS)

{

tmp.Insert(_tables[i]._key,_tables[i]._value);

}

}

_Swap(tmp);

}

}

void _Swap(Dictionary<T, V, HashFunc> tmp)

{

swap(_tables, tmp._tables);

swap(_states, tmp._states);

swap(_capacity, tmp._capacity);

swap(_size, tmp._size);

}

size_t _HashFunonce(const T& key)

{

return key %_capacity;

}

size_t _HashFuntwice(int index,int i)//获取二次探测的下标

{

return (index + i*i) % _capacity;

}

private:

size_t _capacity;

HashTableNode<T,V>* _tables;

State* _states;

size_t _size;

};

}

void test3()//二次探测,负载因子,实现字典的功能

{

/*Third::Dictionary<int, string> h1;

h1.Insert(10, "c语言基础");

h1.Insert(59, "c++基础");

h1.Insert(9, "数据结构");

h1.Insert(19, "Linux");

h1.Insert(18, "网络编程");*/

Third::Dictionary<int,int>h1;

h1.Insert(10, 1);

h1.Insert(59, 2);

h1.Insert(9, 3);

h1.Insert(19,4);

h1.Insert(18, 5);

//h1.Print();

cout<<h1.Find(9)->_value<<endl;

//h1.Remove(9);

//h1.Remove(19);

//h1.Remove(10);

//h1.Print();

}

上述就是对哈希算法的简单应用。

时间: 2024-10-16 20:27:47

哈希表的静态,动态,以及key/value形式的相关文章

哈希表之开散列表——key为字符串.c

#define KEYLENGTH 15 typedef char ElementType[KEYLENGTH+1]; typedef int Index; /*定义单链表*/ typedef struct LNode *PtrToNode; struct LNode{ ElementType Data; PtrToNode Next; }; typedef PtrToNode Position; typedef PtrToNode List; typedef struct TblNode *H

普通集合和泛型集合的区别,哈希表和字典表的区别,队列和堆栈的区别以及堆和栈的区别。

普通集合和泛型集合的区别: 泛型集合与传统集合相比 类型更安全. 泛型集合无需装箱拆箱操作. 泛型的重要性. 泛型是未来五年的主流技术 ... 通常情况下,建议您使用泛型集合,因为这样可以获得类型安全的直接优点而不需要从基集合类型派生并实现类型特定的成员.此外,如果集合元素为值类型,泛型集合类型的性能通常优于对应的非泛型集合类型(并优于从非泛型基集合类型派生的类型),因为使用泛型时不必对元素进行装箱. 下面的泛型类型对应于现有的集合类型: List 是对应于 ArrayList 的泛型类. Di

哈希表算法的编写

哈希算法的编写 hash表,有时候也被称为散列表.个人认为,hash表是介于链表和二叉树之间的一种中间结构.链表使用十分方便,但是数据查找十分麻烦:二叉树中的数据严格有序,但是这是以多一个指针作为代价的结果.hash表既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便. 打个比方来说,所有的数据就好像许许多多的书本.如果这些书本是一本一本堆起来的,就好像链表或者线性表一样,整个数据会显得非常的无序和凌乱,在你找到自己需要的书之前,你要经历许多的查询过程:而如果你对所有的书本进行编号

深入理解哈希表

有两个字典,分别存有 100 条数据和 10000 条数据,如果用一个不存在的 key 去查找数据,在哪个字典中速度更快? 有些计算机常识的读者都会立刻回答: “一样快,底层都用了哈希表,查找的时间复杂度为 O(1)”.然而实际情况真的是这样么? 答案是否定的,存在少部分情况两者速度不一致,本文首先对哈希表做一个简短的总结,然后思考 Java 和 Redis 中对哈希表的实现,最后再得出结论,如果对某个话题已经很熟悉,可以直接跳到文章末尾的对比和总结部分. 哈希表概述 Objective-C 中

哈希表(转)

JAVA哈希表 哈希表是一种重要的存储方式,也是一种常见的检索方法.其基本思想是将关系码的值作为自变量,通过一定的函数关系计算出对应的函数值,把这个数值解释为结点的存储地址,将结点存入计算得到存储地址所对应的存储单元.检索时采用检索关键码的方法.现在哈希表有一套完整的算法来进行插入.删除和解决冲突.在Java中哈希表用于存储对象,实现快速检索. Java.util.Hashtable提供了种方法让用户使用哈希表,而不需要考虑其哈希表真正如何工作. 哈希表类中提供了三种构造方法,分别是: publ

索引器、哈希表Hashtabl、字典Dictionary(转)

一.索引器 索引器类似于属性,不同之处在于它们的get访问器采用参数.要声明类或结构上的索引器,使用this关键字. 示例: 索引器示例代码 /// <summary>/// 存储星期几的类.声明了一个get访问器,它接受字符串,并返回相应的整数/// </summary>public class 星期{    public string[] weeks = { "星期日", "星期一", "星期二", "星期三

哈希表应用

在C#中应用哈希表(Hashtable) 2006-05-24 15:16 491人阅读 评论(0) 收藏 举报 c#stringobjectsystemclass.net 一.哈希表(Hashtable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key/value的键值对,其中key通常可用来快速查找,同时key是区分大小写:value用于存储对应于key的值.Hashtable中key/value

c#哈希表的用法

一,哈希表(Hashtable)简述 在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key/value的键值对,其中key通常可用来快速查找,同时key是区分大小写:value用于存储对应于key的值.Hashtable中key/value键值对均为object类型,所以Hashtable可以支持任何类型的key/value键值对. 二,哈希表的简单操作 在哈希表中添加一个key/value键值对:Hashta

Redis学习笔记09Redis数据类型之(2) 哈希表类型

1.1.1. hset 向hash中添加键值对. 语法: HSET key field value 参数: key :键名称,键值为一个hash表对象. field:hash表中的键名. value:hash表中的键值. 返回值: 整数:1,成功添加了一个原来不存在的新的键对应的键值对. 0,成功的更新了一个原来存在的键对应的键值对. ERROR:key对应的对象存在,但是并不是哈希表类型. 例子: redis.coe2coe.me:6379> hset myhash  host redis.c