哈希表--开散列(哈希桶,拉链法)

##functions.h

#include<stdio.h>
#include<assert.h>
#include<windows.h>

typedef int KeyType;//关键字类型
typedef int ValueType;//个数类型

typedef struct HashNode //哈希链式节点
{
	KeyType _key;//关键字值
	ValueType _value;//个数
	struct HashNode* _next;//指向下个节点的指针
}HashNode;

typedef struct HashTable//哈希表
{

	HashNode** _tables;   // hashnode *表示数组内每个元素类型 ,*table表示数组
	size_t _size;//数组内已用个数
	size_t _capacity;//数组最大容量
}HashTable;

HashNode* BuyHashNode(KeyType key, ValueType value)
{
	HashNode *newnode = (HashNode*)malloc(sizeof(HashNode));
	assert(newnode);
	newnode->_key = key;
	newnode->_next = NULL;
	newnode->_value = value;
	return newnode;
}
void HashPrint(HashTable *ht)
{
	assert(ht);
	for (size_t i = 0;i < ht->_capacity;i++)
	{

		HashNode *cur = ht->_tables[i];
		printf("%d:", i);
		while (cur)
		{
			printf("[%d %d]->", cur->_key, cur->_value);
			cur = cur->_next;
		}
		printf("NULL\n");

	}
}
size_t HashFunc(KeyType key, size_t capacity)
{
	return key % capacity;
}
size_t GetNextPrimeNum(size_t cur)
{
	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 (int i = 0;i < 28;i++)
	{
		if (_PrimeList[i] >(unsigned long)cur)
		{
			return _PrimeList[i];
		}
	}
	return _PrimeList[i];

}
void HashTableInit(HashTable* ht, size_t capacity)
{
	assert(ht);
	ht->_tables = (HashNode**)malloc(sizeof(HashNode*)*capacity);
	assert(ht->_tables);
	ht->_size = 0;
	ht->_capacity = capacity;
	//注意每个数组元素要设置为NULL
	for (size_t i = 0;i < ht->_capacity;i++)
	{
		ht->_tables[i] = NULL;
	}
}
void HashTableDestory(HashTable* ht)
{
	assert(ht);
	for (size_t i = 0;i < ht->_capacity;i++)
	{
		HashNode *cur = ht->_tables[i];
		while (cur)
		{
			HashNode *next = cur->_next;
			free(cur);
			cur = next;
		}
	}
	free(ht->_tables);
	ht->_size = ht->_capacity = 0;

}
void check_capacity(HashTable *ht)
{
	assert(ht);
	if (ht->_size == ht->_capacity)//扩容条件
	{
		HashTable newtable;
		HashTableInit(&newtable, GetNextPrimeNum(ht->_capacity));
		for (size_t i = 0;i < ht->_capacity;i++)//依次将旧表的数据指向新表的映射点
		{
			HashNode *cur = ht->_tables[i];
			while (cur)
			{
				HashNode *next = cur->_next;
				size_t index = HashFunc(cur->_key, newtable._capacity);
				cur->_next = newtable._tables[index];
				newtable._tables[index] = cur;
				cur = next;
			}
		}
		//完成扩容+转移后,仍然使用旧表ht;
		HashTableDestory(ht);
		ht->_tables = newtable._tables;
		ht->_size = newtable._size;
		ht->_capacity = newtable._capacity;

	}
}
void HashTableInsert(HashTable* ht, KeyType key, ValueType value)
{
	assert(ht);
	//检查是否需要扩容
	check_capacity(ht);
	//求映射点
	size_t index = HashFunc(key, ht->_capacity);
	//判断该key值已经在哈希表中
	HashNode *cur = ht->_tables[index];
	while (cur)
	{
		if (cur->_key == key)
		{
			cur->_value++;
			return;

		}
		cur = cur->_next;
	}
	HashNode *newnode = BuyHashNode(key, value);
	newnode->_next = ht->_tables[index];
	ht->_tables[index] = newnode;
	ht->_size++;
}
HashNode* HashTableFind(HashTable* ht, KeyType key)
{
	assert(ht);
	size_t index = HashFunc(key, ht->_capacity);
	HashNode *cur = ht->_tables[index];
	while (cur)
	{
		if (cur->_key == key)
		{
			return cur;
		}
		cur = cur->_next;
	}
	printf("can not find the key!\n");
	return NULL;

}
//成功删除返回1 ,删除失败返回0;
int HashTableRemove(HashTable* ht, KeyType key)
{
	//找映射点,变成从单链表中删除一个节点,删除时检查该key值得
	//value值,如果>1的话减1,如果等于1直接删除。
	assert(ht);
	size_t index = HashFunc(key, ht->_capacity);
	HashNode *cur = ht->_tables[index];
	while (cur)
	{
		if (cur->_key == key)
		{
			if (cur->_value > 1)
			{
				cur->_value--;
				return 1;
			}
			if (cur->_next)
			{
				//要删除的节点value值为1且不是尾节点,可以使用替换法
				HashNode *next = cur->_next;
				cur->_key = next->_key;
				cur->_value = next->_value;
				cur->_next = next->_next;
				free(next);
				next = NULL;
				return 1;
			}
			else
			{
				//说明要删除的节点是尾节点且value值为1
				HashNode *pcur = ht->_tables[index];

				if (pcur = cur)
				{
					//说明该哈希地址出只有1个节点且是要删除的那个
					free(pcur);
					ht->_tables[index] = NULL;
					return 1;
				}
				while (pcur->_next != cur)
				{
					pcur = pcur->_next;
				}
				pcur->_next = NULL;
				free(cur);
				cur = NULL;
				return 1;

			}
		}
		cur = cur->_next;

	}
	return 0;//没有找到
}

##test.c

#include"functions.h"

void test()
{
	HashTable ht;
	HashTableInit(&ht, 13);

	HashTableInsert(&ht, 14, 2);
	HashTableInsert(&ht, 27, 1);
	HashTableInsert(&ht, 1, 1);
	HashTableInsert(&ht, 3, 1);

	HashPrint(&ht);
	printf("\n\n");
	HashTableRemove(&ht,14);
	


	HashPrint(&ht);



}

int main()
{
	test();
	system("pause");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值