哈希表--开放定制法 练习

#functions.h

#include<stdio.h>
#include<windows.h>
#include<assert.h>
typedef int KeyType; //关键字类型
typedef int ValueType;//个数类型

typedef enum type //类型
{
	_EMPTY,
	_EXIST,
	_DELETE
}type;

typedef struct HashNode //哈希节点
{
	type status;//状态
	KeyType _key;//关键字数值
	ValueType _value;//个数
	
}HashNode;

typedef struct HashTable//ha哈希表
{
	HashNode* _tables;
	size_t _size;//
	size_t _capacity;
}HashTable;


void HashTableInit(HashTable* ht,int size)
{
	assert(ht);
	ht->_tables = (HashNode *)malloc(sizeof(HashNode) * size);
	assert(ht->_tables);
	ht->_size = 0;
	ht->_capacity = size;
	for (size_t i = 0;i < ht->_capacity;i++)
	{
		ht->_tables[i].status = _EMPTY;
	}
}
void hashprint(HashTable *ht)
{
	assert(ht);
	assert(ht->_size > 0);
	for (size_t i = 0;i < ht->_capacity;i++)
	{
		if (ht->_tables[i].status == _EXIST)
		{
			printf("%d: [key:%d  value:%d]\n",i, ht->_tables[i]._key, ht->_tables[i]._value);
		}
		else
		{
			printf("%d: EMPTY\n",i);
		}
	}
}
int FindNextPrime(int size)
{
	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)size)
		{
			return _PrimeList[i];
		}
	}
	return _PrimeList[i];
}

size_t hashfunc(HashTable *ht,KeyType key)
{
	return key % (ht->_capacity);
}
void  HashTableInsert(HashTable* ht, KeyType key, ValueType value)
{
	//往哈希表中插入值。成功返回1,失败返回0;
	//判断是否超过负载因子0.7,超过则重新申请新表,重新计算并插入所有数据。
	//用开放定址法确定要插入的下标。更改数值,状态,个数。
	assert(ht);
	size_t load = (ht->_size) / (ht->_capacity);
	if (load * 10 > 7)
	{
		//说明已经大于负载因子0.7,这时如果不扩容再插入哈希表,冲突的概率很大
		HashTable newtable;//建新表
		HashTableInit(&newtable, FindNextPrime(ht->_capacity));

		for (size_t i = 0;i < ht->_capacity;i++)//重新计算哈希值并插入
		{
			HashTableInsert(&newtable, (ht->_tables[i])._key, (ht->_tables[i])._value);
		}
		free(ht->_tables);
		ht->_tables = newtable._tables;
		ht->_size = newtable._size;
		ht->_capacity = newtable._capacity;

	}
	size_t index = hashfunc(ht, key);
	if (ht->_tables[index].status == _EXIST && ht->_tables[index]._key == key)
	{
		value++;
		return;
	}
	while (ht->_tables[index].status == _EXIST)
	{
		index++;
		if (index == ht->_capacity)
		{
			index = 0;
		}
	}
	
	
	ht->_tables[index]._key = key;
	ht->_tables[index]._value = value;
	ht->_tables[index].status = _EXIST;
	ht->_size++;
	

}
HashNode* HashTableFind(HashTable* ht, KeyType key)
{
	assert(ht);
	size_t index = hashfunc(ht,key);
	size_t flag = index;
	while (ht->_tables[index].status != _EMPTY)
	{
		if (ht->_tables[index]._key == key)
		{
			return &(ht->_tables[index]);
		}
		if (index == ht->_capacity)
		{
			index = 0;
			continue;
		}
		++index;
	}
	return NULL;
	
}
int HashTableRemove(HashTable* ht, KeyType key)
{
	//在哈希表中删除关键字key
	assert(ht);
	size_t index = hashfunc(ht, key);
	while (ht->_tables[index].status == _EXIST)
	{
		if (ht->_tables[index]._key == key)
		{
			ht->_tables[index].status = _EMPTY;
			return 1;
		}
		if (index == ht->_capacity)
		{
			index = 0;
			continue;
		}
		index++;
	}
	

}
void HashTableDestory(HashTable* ht)
{
	assert(ht);
	free(ht->_tables);
	ht->_tables = NULL;
	ht->_size = ht->_capacity = 0;
}

#test.c

#include"functions.h"



void test()
{
	HashTable ht;
	HashTableInit(&ht,13);
	HashTableInsert(&ht, 13, 1);
	HashTableInsert(&ht, 44, 2);
	HashTableInsert(&ht, 0, 1);
	printf("%d\n", (ht._tables[0])._key);
	printf("%d\n", HashTableFind(&ht, 0)->_key);	
	hashprint(&ht);
	HashTableRemove(&ht, 13);
	hashprint(&ht);
	HashTableDestory(&ht);
}


int main()
{
	test();
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
链地址哈希表解决冲突的一种方,它的基本思想是将哈希表中的每个槽作为一个链表的头结点,将哈希值相同的元素插入到相应的链表中。 在链地址中,每个槽都是一个链表的头结点,每个元素都被插入到相应槽对应的链表中。当发生哈希冲突时,只需要在相应槽对应的链表中插入新元素即可。 具体实现时,可以使用一个数组来存储链表的头结点。插入元素时,先计算出它在哈希表中的位置,然后将它插入到相应槽对应的链表的头部即可。 下面是一个使用链地址解决哈希冲突的示例代码: ```python class Node: def __init__(self, val): self.val = val self.next = None class HashTable: def __init__(self, size): self.size = size self.table = [None] * size def hash(self, val): return val % self.size def insert(self, val): index = self.hash(val) node = Node(val) node.next = self.table[index] self.table[index] = node def search(self, val): index = self.hash(val) node = self.table[index] while node: if node.val == val: return True node = node.next return False def delete(self, val): index = self.hash(val) node = self.table[index] if not node: return False if node.val == val: self.table[index] = node.next return True while node.next: if node.next.val == val: node.next = node.next.next return True node = node.next return False ``` 在这个实现中,我们使用了一个 `Node` 类来表示链表中的节点。在 `HashTable` 类中,我们使用一个数组 `table` 来存储链表的头结点。`hash` 方用来计算元素的哈希值。`insert` 方用来插入元素,将它插入到相应槽对应的链表的头部。`search` 方用来查找元素,遍历相应槽对应的链表,直到找到元素或遍历完链表。`delete` 方用来删除元素,首先需要遍历相应槽对应的链表,找到要删除的元素,然后将它从链表中删除即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值