1、哈希表
说明1
说明2
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表hashtable(key,value) 就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。参考
1、利用链地址法实现
一个散列函数能够将键转化为数组索引。散列算法的第二步就是碰撞处理,也就是处理两个或多个键的散列值相同的情况。拉链法就是将大小为M 的数组中的每个元素指向一条链表,链表中的每个结点都存储了散列值为该元素的索引的键值对。这个方法的思想就是选择足够大的M,使得所有链表都尽可能短以保障高效的查找,否则容易退化成单链表的情况。如下图中M=5:
参考
// 哈希函数.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<memory.h>
#include<iostream>
using namespace std;
class HashTable
{
public:
typedef struct _HashNode//哈希节点
{
int key;//值
_HashNode* pNext;//指向下一个节点的值
}HashNode;
typedef struct _Hash
{
_HashNode* pElement;//数据元素的存放空间
}_Hash;
public:
void InitHashTable(int len);//初始化哈希表
int Hash(int key);//计算哈希值
void InsertData(int key);//插入数据
HashNode* SearchTable(int key, int *addr);//查找数据
void CreateTable(int array[], int n);//建立哈希表
void ShowHash();//显示数据
private:
_Hash m_hashTable;//哈希表
int m_tableLength;//哈希表长
};
int _tmain(int argc, _TCHAR* argv[])
{
HashTable hash;
hash.InitHashTable(7);
int arr[] = { 19, 1, 23, 14, 55, 68, 11, 82, 36 };
hash.CreateTable(arr, 9);
hash.ShowHash();
int addr = 0;
HashTable::_HashNode* pNode = hash.SearchTable(19, &addr);
cout << "找到的值是:" << pNode->key <<endl<< "地址为:" << addr << endl;
return 0;
}
void HashTable::InitHashTable(int len)
{
m_tableLength = len;
m_hashTable.pElement = new _HashNode[len];//开辟存放数组元素空间
memset(m_hashTable.pElement, 0x00, sizeof(_HashNode)*len);
}
int HashTable::Hash(int key)//哈希值
{
return key%m_tableLength;//数组元素对表长取余就是哈希值
}
void HashTable::InsertData(int key)
{
int addr = Hash(key);//获取哈希值
if (m_hashTable.pElement[addr].key==0)//判断是否存在哈希冲突
{
m_hashTable.pElement[addr].key = key;//将要插入的值放在对应的位置
}
else
{
_HashNode* pNew = new _HashNode;//新建一个节点
pNew->key = key;//将值赋值给新节点
pNew->pNext = m_hashTable.pElement[addr].pNext;//将新节点指向的下一个位置置为空
m_hashTable.pElement[addr].pNext = pNew;//新节点放在上一个点的后面
}
}
void HashTable::CreateTable(int array[], int n)//将数组的数据插在哈希表中
{
for (int i = 0; i < n; i++)
{
InsertData(array[i]);
}
}
void HashTable::ShowHash()
{
for (int i = 0; i < m_tableLength; i++)
{
cout << "第" << i << ":";
_HashNode* pNode = &(m_hashTable.pElement[i]);
while (pNode)
{
cout << pNode->key << " ";
pNode = pNode->pNext;
}
cout << endl;
}
}
HashTable::HashNode* HashTable::SearchTable(int key, int* addr)
{
*addr = Hash(key);
_HashNode* pNode = &(m_hashTable.pElement[*addr]);
while (pNode)
{
if (pNode->key==key)
{
return pNode;
}
pNode = pNode->pNext;//继续查找
}
return pNode;
}
2、利用开放地址法实现
这个方法的基本思想是:当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。这个过程可用下式描述:
H i ( key ) = ( H ( key )+ d i ) mod m ( i = 1,2,…… , k ( k ≤ m – 1))
其中: H ( key ) 为关键字 key 的直接哈希地址, m 为哈希表的长度, di 为每次再探测时的地址增量。
采用这种方法时,首先计算出元素的直接哈希地址 H ( key ) ,如果该存储单元已被其他元素占用,则继续查看地址为 H ( key ) + d 2 的存储单元,如此重复直至找到某个存储单元为空时,将关键字为 key 的数据元素存放到该单元。
增量 d 可以有不同的取法,并根据其取法有不同的称呼:
( 1 ) d i = 1 , 2 , 3 , …… 线性探测再散列;
( 2 ) d i = 1^2 ,- 1^2 , 2^2 ,- 2^2 , k^2, -k^2…… 二次探测再散列;
( 3 ) d i = 伪随机序列 伪随机再散列;
参考
#include"stdafx.h"
#include<iostream>
#include<memory.h>
using namespace std;
class HashTable
{
public:
typedef struct _Hash
{
int *pElement;//存放数组
int nCount;//数组元素个数
}_Hash;
void InitHashTable(int len);//初始化数组
int Hash(int key);//计算函数值
void InsertData(int key);
void CreatHashTable(int array[], int n);
bool SearchHash(int key, int *addr);
void ShowHash();
private:
_Hash hashTable;
int TableLen;
};
int _tmain(int argc, _TCHAR* argv[])
{
HashTable hashK;
hashK.InitHashTable(17);
int arr[] = { 47, 7, 29, 11, 16, 92, 22, 8, 3 };
hashK.CreatHashTable(arr, 9);
hashK.ShowHash();
int addr = 0;
bool ret = hashK.SearchHash(29, &addr);
cout << "查找结果 : " << ret << "\t地址为 : " << addr << endl;
return 0;
}
void HashTable::InitHashTable(int len)
{
TableLen = len;
hashTable.pElement = new int[len];
hashTable.nCount = 0;
memset(hashTable.pElement, 0x00, sizeof(int)*len);
}
int HashTable::Hash(int key)
{
return key%TableLen;
}
void HashTable::InsertData(int key)
{
if (hashTable.nCount>=TableLen)
{
return;
}
int addr = Hash(key);
while (hashTable.pElement[addr]!=0)//有冲突就将余数+1再继续处理
{
addr = (addr + 1) % TableLen;
}
hashTable.pElement[addr] = key;
hashTable.nCount++;
}
void HashTable::CreatHashTable(int array[], int n)
{
for (int i = 0; i < n; i++)
{
InsertData(array[i]);
}
}
bool HashTable::SearchHash(int key, int *addr)
{
*addr = Hash(key);
int nCount = 0;
while (hashTable.pElement[*addr]!=0)
{
*addr = (*addr + 1) % TableLen;
if (++nCount>TableLen)
{
return false;
}
}
return true;
}
void HashTable::ShowHash()
{
for (int i = 0; i < TableLen; i++)
{
cout << "第" << i <<" "<< hashTable.pElement[i] << endl;
}
}