哈希表的基础操作--开放定址法

HashTable.h

#pragma once

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>

typedef int HTKeyType;
typedef char HTValueType;
//枚举哈希表中每一个数据的三种状态
typedef enum State
{
	EMPTY,//空
	EXITST,//存在数据
	DELETE//已被删除
}State;
//定义哈希表中数据类型
typedef struct HashData
{
	State _state;//状态
	HTKeyType _key;//key-value
	HTValueType _value;//key-value
}HashData;
//定义哈希表的结构
typedef struct HashTable
{
	HashData* _table;//动态数组实现
	int _len;//表长
	int _size;//有效元素的个数
}HashTable;



//哈希表的初始化
void HashTableInit(HashTable* ht, size_t len);
//销毁哈希表(malloc出来的空间)
void HashTableDestroy(HashTable* ht);
//向哈希表中插入一个值
int HashTableInsert(HashTable* ht, HTKeyType key, HTValueType value);
//在哈希表中删除一个值
int HashTableRemove(HashTable* ht, HTKeyType key);
//在哈希表中查找一个值
HashData* HashTableFind(HashTable* ht, HTKeyType key);
//判断哈希表是否为空(空返回0,非空返回1)
int HashTableEmpty(HashTable* ht);
//哈希表的有效元素个数
int HashTableSize(HashTable* ht);
//打印哈希表中的数据
void PrintHashTable(HashTable* ht);

HashTable.c

#include "HashTable.h"

static size_t GetNextPrime(size_t value)//质数表,给增容提供最佳选择容量大小
{
	int i = 0;
	//const int _PrimeSize = 28;
	static const unsigned long _PrimeList[28] =
	{
		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
	};

	for (; i < 28; ++i)
	{
		if (_PrimeList[i] > value)
		{
			return _PrimeList[i];
		}
	}

	return _PrimeList[27];
}

void HashTableInit(HashTable* ht, size_t len)
{

	size_t i;
	assert(len > 0);
	assert(ht);

	len = GetNextPrime(len);
	ht->_table = (HashData*)malloc(sizeof(HashData)*len);//动态开辟一个数组
	memset(ht->_table, 0, sizeof(HashData)*len);
	ht->_size = 0;//有效元素的个数
	ht->_len = len;//哈希表的长度

	for (i = 0; i < len; ++i)//首先将所有数据的状态都设置为空(EMPTY)
	{
		ht->_table[i]._state = EMPTY;
	}
}

void HashTableDestroy(HashTable* ht)
{
	assert(ht);
	free(ht->_table);
	ht->_table = NULL;
	ht->_len = 0;
	ht->_size = 0;
}

//检查负载因子是否达到了上限(规定为0.7),如果达到上限,则要给哈希表扩容
void CheckCapacity(HashTable*ht)
{
	//思路:开辟一个新的哈希表,先遍历一遍旧哈希表,将所有的数据转移到新的哈希表
	//在将旧哈希表销毁,最后将新的哈希表给旧哈希表维护的指针
	assert(ht);
	HashTable newht;
	int len = (ht->_len) * 2;
	if (((ht->_size) * 10) / ht->_len > 7)//负载因子计算(整数无法与浮点数比较,所以同时扩大十倍)
	{
		HashTableInit(&newht,len);
		//遍历一遍旧哈希表,将所有的数据转移到新的哈希表
		int i = 0;
		for (i = 0; i < ht->_len; i++)
		{
			if (ht->_table[i]._state == EMPTY)
			{
				HashTableInsert(&newht, ht->_table[i]._key, ht->_table[i]._value);
			}
		}
		//销毁旧表
		HashTableDestroy(ht);
		//将新的哈希表给旧哈希表维护的指针
		ht->_table = newht._table;
		ht->_size = newht._size;
		ht->_len = newht._len;
	}
}
//哈希函数,根据哈希函数得到一个地址(采用模留余数法)
int GetPosition(HashTable* ht, HTKeyType key)
{
	assert(ht);
	return key % (ht->_len);
}
int HashTableInsert(HashTable* ht, HTKeyType key, HTValueType value)
{
	assert(ht);
	//检查容量是否达到最大负载因子,达到则扩容
	CheckCapacity(ht);
	//1.确定插入的位置
	int index = GetPosition(ht, key);
	//2.如果有冲突,处理冲突(闭散列线性探测)
	while (ht->_table[index]._state == EXITST)
	{
		//如果表中有要插入的数据,则插入失败
		if (ht->_table[index]._key == key)
		{
			return 0;
		}
		else
		{
			index++;
		}
	}
	//3.找到插入位置,直接插入
	ht->_table[index]._state = EXITST;
	ht->_table[index]._key = key;
	ht->_table[index]._value = value;
	ht->_size++;
}

int HashTableRemove(HashTable* ht, HTKeyType key)
{
	assert(ht);
	//1.找到要删除元素的位置
	HashData* ret = HashTableFind(ht, key);
	//2.不为空则找到,直接修改状态删除,删除成功返回1
	if (ret)
	{
		ht->_size--;
		ret->_state = DELETE;
		return 1;
	}
	//删除失败返回0
	return 0;
}

HashData* HashTableFind(HashTable* ht, HTKeyType key)
{
	assert(ht);
	//1.根据哈希哈数先确定哈希地址
	int index = GetPosition(ht, key);
	//2.如果有冲突,按照处理冲突的方法再去查找
	while (ht->_table[index]._state != EMPTY)
	{
		if (ht->_table[index]._key == key)
		{
			//找到数据并且状态为存在则返回它的地址
			if (ht->_table[index]._state == EXITST)
			{
				return &ht->_table[index];
			}
			//状态为删除状态,说明要找的数据已经被删除,直接返回
			else
			{
				return NULL;
			}
		}
		//按照处理冲突的方法线性探测继续查找
		else
		{
			++index;
		}
	}
	//找到空说明没有找到
	return NULL;
}

int HashTableEmpty(HashTable* ht)
{
	assert(ht);
	return ht->_size == 0 ? 0 : 1;
}

int HashTableSize(HashTable* ht)
{
	assert(ht);
	return ht->_size;
}

void PrintHashTable(HashTable* ht)
{
	assert(ht);
	int i = 0;
	for (i = 0; i < ht->_len; i++)
	{
		if (ht->_table[i]._state == EXITST)
		{
			printf("[%d](%d:%c)\n", i, ht->_table[i]._key, ht->_table[i]._value);
		}
	}
	printf("\n");
}




void TestHashTable()
{
	HashTable ht;
	HashTableInit(&ht, 5);
	HashTableInsert(&ht, 15, 'f');
	HashTableInsert(&ht, 24, 't');
	HashTableInsert(&ht, 56, 's');
	HashTableInsert(&ht, 71, 's');
	HashTableInsert(&ht, 23, 's');
	HashTableInsert(&ht, 46, 's');
	HashData* ret = HashTableFind(&ht, 71);
	printf("state:%d,key;%d,value:%c\n", ret->_state, ret->_key, ret->_value);
	printf("哈希表的大小:%d\n", HashTableSize(&ht));
	HashTableRemove(&ht, 15);
	printf("哈希表的大小:%d\n", HashTableSize(&ht));
	HashTableInsert(&ht, 59, 's');
	HashTableInsert(&ht, 31, 's');
	printf("哈希表的大小:%d\n", HashTableSize(&ht));
	PrintHashTable(&ht);
	HashTableDestroy(&ht);

}


int main()
{
	TestHashTable();
	return 0;
}

运行结果如下:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值