数据结构-HashTable(哈希表/散列表)

哈希表是什么?

哈希表(HashTable)又叫做散列表,是根据关键码值(即键值对)而直接访问的数据结构。也就是说,它通过把关键码映射到表中一个位置来访问记录,以加快查找速度。看到这里你可能比较疑惑,它是怎么加快查找速度的?下一节就有说明!这个映射函数就叫做散列(哈希)函数,存放记录的数组叫做散列表。

为什么哈希表的速度快? 

数据结构中,我们对两种数据结构应该会非常熟悉:数组与链表。数组的特点就是查找容易,插入删除困难;而链表的特点就是查找困难,但是插入删除容易。既然两者各有优缺点,那么我们就将两者的有点结合起来,让它查找容易,插入删除也会快起来。哈希表就是讲两者结合起来的产物。

哈希如何查找?

哈希的查找就是下面两个步骤:

<1>使用哈希函数将被查找的键转化为数组的索引。在理想的状态下,不同的键会被转化成不同的索引值。但是那是理想状态,我们实践当中是不可能一直是理想状态的。当不同的键生成了相同的索引的时候,也就是我们所说的冲突,我们这个时候就要处理冲突。

<2> 处理冲突的方法很多,后面我们介绍线性探索法拉链法

哈希表是一个时间和空间上平衡的例子。如果没有空间的限制,我们可以直接用键来作为数组的索引,这样可以将查找时间做到最快(O(1))。如果没有时间的限制,我们可以使用无序链表进行顺序查找,这样只需要很少的内存。

什么是哈希函数?

哈希函数其实就是我们常说的哈希算法,主要应用在以下这几个方面:文件校验、数字签名、鉴权协议。常用的哈希算法有以下这些。

<1>MD5:MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。MD5是输入不定长度信息,输出固定长度128bits的算法。

<2>SHA-1:常用于HTTPS传输和软件签名。

<3>SHA-2:SHA-224/SHA-256/SHA-384/SHA-512并成为SHA-2

<4>SHA-3:之前名为Keccak算法,是一个加密杂凑算法。

如何避免哈希冲突?

拉链法

线性探索法

 

 

HashTable结构

#define HASHTABLESIZE  13
typedef  int  KeyType;
// typedef  int  DataType;

typedef struct Node
{
    KeyType  key;   //   数据原有的key值,此值一般不能有重复的  主键(唯一)
    // DataType   data;
    struct Node *next;
}LinkList;

typedef struct Hash
{
    LinkList *hash_table[HASHTABLESIZE];
    int   number[HASHTABLESIZE];    //  记录每一个链表的节点的个数
}Hash;

HashTable实现

#include "hash.h"

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <math.h>

//初始化哈希表
void InitHash(Hash *hash)
{
	if(hash == NULL)  exit(0);

	for(int i = 0; i < HASHTABLESIZE; ++i)
	{
		hash->hash_table[i] = NULL;
		hash->number[i] = 0;
	}
}

//定义哈希函数
static int HashFun(KeyType key)
{
	return abs(key % HASHTABLESIZE);//abs取绝对值,key%HASHTABLESIZE 得到存放数组的下标
}

//插入元素
int InsertHash(Hash *hash, KeyType key)
{
	if(hash == NULL)  exit(0);

	int hash_key = HashFun(key); //hash_key 就是下标

	LinkList *p = hash->hash_table[hash_key];

	while(p != NULL)
	{
		if(p->key == key)  return 0;//判断key是否存在 是否唯一
		p = p->next;
	}

	LinkList *new_node = (LinkList*)malloc(sizeof(LinkList));
	if(new_node == NULL)  return 0;

	new_node->key = key; 
	new_node->next = hash->hash_table[hash_key]; //新结点next指向原先结点,若原先没有结点即指向NULL
	hash->hash_table[hash_key] = new_node;
	hash->number[hash_key]++;

	return 1;
}

//删除哈希元素
int DeleteHash(Hash *hash, KeyType key)
{
	if(hash == NULL)  exit(0);

	int hash_key = HashFun(key);

	LinkList *p = hash->hash_table[hash_key];
	LinkList *q = NULL; //  p的前驱节点

	while(p != NULL)
	{
		if(p->key == key)//遍历寻找需要删除的结点
		{
			if(q == NULL)
			{
				hash->hash_table[hash_key] = p->next;
			}
			else
			{
				q->next = p->next;
			}

			free(p);
			hash->number[hash_key]--;
			return 1;
		}

		q = p;
		p = p->next;
	}

	return 0;
}

//查询,与上面插入或删除时相同
LinkList *Search(Hash *hash, KeyType key)
{
	if(hash == NULL) exit(0);

	int hash_key = HashFun(key);

	LinkList *p = hash->hash_table[hash_key];

	while(p != NULL)
	{
		if(p->key == key) return p;

		p = p->next;
	}

	return NULL;

}
//销毁哈希表
void DestroyHash(Hash *hash)
{
	if(hash == NULL) exit(0);

	for(int i = 0; i < HASHTABLESIZE; ++i)
	{
		LinkList *p = hash->hash_table[i];
		while(p != NULL)
		{
			hash_table[i] = p->next;
			free(p);
			p = hash_table[i];
		}

		hash->number[i] = 0;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安冉冄先森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值