哈希表的实现

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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值