哈希表—闭散列

哈希表的基本概念

操作

  • 插入元素时:根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
  • 搜索元素时:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键 码相等,则搜索成功

哈希冲突

不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞

负载因子

负载因子 = 表中元素个数 / 列表长度

闭散列

当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到表中 “下一个” 空位中去(负载因子a不超过 0.7;如果超出必须考虑增容 )

解决哈希冲突的方法

线性探测——从发生冲突的位置开始,依次继续向后探测,直到找到空位置为止
二次探测——发生哈希冲突时,二次探查法在表中寻找“下一个”空位置的公式为: Hi = (H0 + i^2) % m, Hi= ( H0 - i^2) % m, i = 1,2,3…, (m-1)/2H0是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小

辅助定义

#define MAX_SIZE 10   //初始大小
typedef int HDataType;
enum State
{
	EMPTY,  //空
	EXTXT,  //存储
	DELET,  //删除
};
typedef struct HTELEM  //哈希表中存储的元素数字及状态
{
	HDataType _data;  //数据
	enum State _state;  //状态
}HTELEM, *pHTELEM;

静态实现

定义

typedef struct HashTable
{
	HTELEM _ht[MAX_SIZE];  //哈希表
	int _size; //元素个数
}HashTable, *pHashTable;

哈希函数

int HashFun(HDataType data) //哈希函数
{
	return (data % 10);
}

初始化

void HashInit(pHashTable phashtable)
{
	//静态
	assert(phashtable); //指针不能为空
	//状态置空
	for (int i = 0; i < MAX_SIZE; i++)
	{
		phashtable->_ht[i]._state = EMPTY;
	}
	//元素个数初始值为0
	phashtable->_size = 0;
}

元素个数

int HashSize(pHashTable phashtable)
{
	assert(phashtable);
	return phashtable->_size;
}

哈希表是否为空

int HashEmpty(pHashTable phashtable)
{
	assert(phashtable);
	return phashtable->_size == 0;
}

插入

void HashInsert(pHashTable phashtable, HDataType data)
{
	//静态
	assert(phashtable);
	//计算哈希地址
	int address = HashFun(data);
	int i = 1;
	while (phashtable->_ht[address]._state != EMPTY)
	{
		//线性探测
		address = address + 1;
		if (address == MAX_SIZE)
			address = 0;
		/*
		//二次探测
		address = (address + i * i) % MAX_SIZE;
		i++;
		if (address == MAX_SIZE)
			address = 0;
		*/
	}
	//插入元素
	phashtable->_ht[address]._data = data;
	phashtable->_ht[address]._state = EXTXT;
	phashtable->_size++;

}

查找

int HashFind(pHashTable phashtable, HDataType data)
{
	//静态
	assert(phashtable);
	//计算哈希地址
	int address = HashFun(data);
	int i = 1;
	//状态不为空,且状态为存储状态,查找元素
	while (phashtable->_ht[address]._state != EMPTY)
	{
		//线性探测规则查找
		if (phashtable->_ht[address]._state == EXTXT)
		{
			if (phashtable->_ht[address]._data == data)
			{
				return address;
			}
		}
		//线性探测
		address = address + 1;
		if (address == MAX_SIZE)
			address = 0;
		/*
		//二次探测
		address = (address + i * i) % MAX_SIZE;
		i++;
		if (address == MAX_SIZE)
			address = 0;
		*/
	}
	return -1;
}

删除

int HashDelete(pHashTable phashtable, HDataType data)
{
	//静态
	assert(phashtable);
	//计算哈希地址
	int address = HashFun(data);
	int i = 1;
	//状态不为空,且状态为存储状态,查找元素,改变状态
	while (phashtable->_ht[address]._state != EMPTY)
	{
		//线性探测规则查找
		if (phashtable->_ht[address]._state == EXTXT)
		{
			if (phashtable->_ht[address]._data == data)
			{
				phashtable->_ht[address]._state = DELET;
				return 1;
			}
		}
		//线性探测
		address = address + 1;
		if (address == MAX_SIZE)
			address = 0;
		/*
		//二次探测
		address = (address + i * i) % MAX_SIZE;
		i++;
		if (address == MAX_SIZE)
			address = 0;
		*/
	}
	return 0;
}

动态实现

定义

typedef struct HashTableDy
{
	pHTELEM _ht;  //哈希链表表
	int _size; //元素个数
	int _capacity;  //容量  最大元素个数
	int _totly;  //已经使用位置个数
}HashTableDy, *pHashTableDy;

哈希函数

int HashFunDy(HDataType data, int capacity)
{
	return data % capacity;
}

初始化

void HashInit(pHashTableDy phashtabledy, int capacity)
{
	assert(phashtabledy); //指针不能为空
	//开辟空间
	pHTELEM ph = (pHTELEM)malloc(capacity * sizeof(HTELEM));
	if (NULL == ph)
	{
		assert(0);
	}
	//状态置空
	for (int i = 0; i < capacity; i++)
	{
		(ph + i)->_state = EMPTY;
	}
	phashtabledy->_ht = ph;
	//初始化容量
	phashtabledy->_capacity = capacity;	
	//元素个数初始值为0
	phashtabledy->_size = 0;
	phashtabledy->_totly = 0;
}

元素个数

int HashSize(pHashTableDy phashtabledy)
{
	assert(phashtabledy);
	return phashtabledy->_size;
}

哈希表是否为空

int HashEmpty(pHashTableDy phashtabledy)
{
	assert(phashtabledy);
	return phashtabledy->_size == 0;
}

插入

扩容函数
void Dilatation(pHashTableDy *phashtabledy)
{
	//开辟新空间,为原空间的两倍
	int capacity = (*phashtabledy)->_capacity * 2;
	pHTELEM ph = (pHTELEM)malloc(capacity * sizeof(HTELEM));
	if (NULL == ph)
	{
		assert(0);
	}
	//新空间的状态为空
	for (int i = 0; i < capacity; i++)
	{
		(ph + i)->_state = EMPTY;
	}
	//拷贝元素
	for (int i = 0; i < (*phashtabledy)->_capacity; i++) //遍历原空间
	{
		if (((*phashtabledy)->_ht + i)->_state == EXTXT)  //存在元素
		{
			//插入到新空间
			int address = HashFunDy(((*phashtabledy)->_ht + i)->_data, capacity);
			while ((ph + address)->_state != EMPTY)
			{
				//线性探测
				address = address + 1;
				if (address == MAX_SIZE)
					address = 0;
				/*
				//二次探测
				address = (address + i * i) % MAX_SIZE;
				i++;
				if (address == MAX_SIZE)
					address = 0;
				*/
			}
			//插入元素
			(ph + address)->_data = ((*phashtabledy)->_ht + i)->_data;
			(ph + address)->_state = EXTXT;
		}
	}
	//释放旧空间
	(*phashtabledy)->_capacity = capacity;
	(*phashtabledy)->_totly = (*phashtabledy)->_size;
	pHTELEM del = (*phashtabledy)->_ht;
	(*phashtabledy)->_ht = ph;
	free(del);
	del = NULL;
}
插入
void HashInsert(pHashTableDy phashtabledy, HDataType data)
{
	//静态
	assert(phashtabledy);
	//判断是否需要开辟空间-负载因子
	if ((phashtabledy->_totly) * 10 / phashtabledy->_capacity >= 7)
	{
		//扩容
		Dilatation(&phashtabledy); 
	}
	//计算哈希地址
	int address = HashFunDy(data, phashtabledy->_capacity);
	while ((phashtabledy->_ht + address)->_state != EMPTY)
	{
		//线性探测
		address = address + 1;
		if (address == MAX_SIZE)
			address = 0;
		/*
		//二次探测
		address = (address + i * i) % MAX_SIZE;
		i++;
		if (address == MAX_SIZE)
			address = 0;
		*/
	}
	//插入元素
	(phashtabledy->_ht + address)->_data = data;
	(phashtabledy->_ht + address)->_state = EXTXT;
	phashtabledy->_size++;
	phashtabledy->_totly++;
}

查找

int HashFind(pHashTableDy phashtabledy, HDataType data)
{
	assert(phashtabledy);
	//计算哈希地址
	int address = HashFunDy(data, phashtabledy->_capacity);
	//状态不为空
	while ((phashtabledy->_ht + address)->_state != EMPTY)
	{
		//线性探测规则查找
		if ((phashtabledy->_ht + address)->_state == EXTXT)
		{
			if ((phashtabledy->_ht + address)->_data == data)
			{
				return address;
			}
		}
		//线性探测
		address = address + 1;
		if (address == MAX_SIZE)
			address = 0;
		/*
		//二次探测
		address = (address + i * i) % MAX_SIZE;
		i++;
		if (address == MAX_SIZE)
			address = 0;
		*/
	}
	return -1;
}

删除

int HashDelete(pHashTableDy phashtabledy, HDataType data)
{
	assert(phashtabledy);
	//计算哈希地址
	int address = HashFunDy(data, phashtabledy->_capacity);
	//状态不为空
	while ((phashtabledy->_ht + address)->_state != EMPTY)
	{
		//线性探测规则查找
		if ((phashtabledy->_ht + address)->_state == EXTXT)
		{
			if ((phashtabledy->_ht + address)->_data == data)
			{
				(phashtabledy->_ht + address)->_state = DELET;
				return 1;
			}
		}
		//线性探测
		address = address + 1;
		if (address == MAX_SIZE)
			address = 0;
		/*
		//二次探测
		address = (address + i * i) % MAX_SIZE;
		i++;
		if (address == MAX_SIZE)
			address = 0;
		*/
	}
	return -1;
}

销毁

void HashDestroy(pHashTableDy phashtabledy)
{
	assert(phashtabledy);
	free(phashtabledy->_ht);
	phashtabledy->_ht = NULL;
	phashtabledy->_capacity = 0;
	phashtabledy->_size = 0;
	phashtabledy->_totly = 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值