哈希表之拉链法

前段时间理解了一下所谓的哈希表,一直以来在小博印象中哈希表是深奥的,是高大上的,但是接触原理以及看了一份demo之后我就觉得哈希表也就那样吧,接下来我把小博自己的理解尽量用最直白的语句来解释下~~~

---------------------------------------------------------我是分界线,没错,很丑------------------------------------------------------------------

首先什么是哈希表???

散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

以上是一段在百度百科中的解释,如果还是不能理解,那么我就抽象的比喻一下。

先看(是根据关键码值(Key value)而直接进行访问的数据结构),这里的关键码值以及数据结构可以用具体的物体代替一下,这里小博将关键码值用学号代替,数据结构用学生代替,学生与学号都是唯一的,可以根据学号直接找到学生。(说了一堆废话~~~~接下去才是重点)。

场景演示一下,当我们需要将数据存入哈希表中的时候,就好像是一堆学生在办理入学,那么这时候有个地中海的大肚子男老师过来了,他对每个上前办理的学生说:你是XXX号,你所在的班级是YYY班,记住咯。然后这名学生就屁颠屁颠的去YYY班了。那么怎么查找呢??想必在学校中被校长点名过的同学应该都想到了,比如XXX号犯错了,他所在的班级是YYY一班,那么校长会说,在YYY一班的XXX号,你出来一下咱们好好喝喝茶~~这样校长就不用为了找XXX号同学而找遍每一个学生了,相对来说就是提升了查找效率。这是哈希表其中的一个特性————查找方便

还有一个比较重要的特性,小博暂时没想到怎么怎么形象的比喻(原谅小博的见识浅薄~~囧)。另一个特性是空间高利用率,各位大老爷可能有几个一下子不能理解这个,请容小博详细说明,都知道需要存数据是需要容器的,数组,结构体等都是容器的一种,那么只要是容器都需要各自的空间(其实不仅仅是容器需要,其他也是一样的,但是相比之下其他占用的比较少罢了,继续正文),比如数组,当申请的时候需要一块连续的空间,而数据结构也是如此,申请的时候需要一块整个数据结构大小的空间,而且每次申请空间的时候,系统内部所为你划分的空间并不是一块挨着一块申请的,因此肯定会有少部分空间无法申请导致浪费,采用数据结构可以灵活的利用这些空间,采用链表将每个结构体联系起来,那么就形成了一个最简单的哈希表。直接上代码理解一下吧~~~~(写这些的时候小博已经神游,断片了,原谅小博的才疏学浅。)

#include <stdio.h>
#include <string>
#include <time.h>

typedef struct ITEM
{
	int val;
	int index;
	struct ITEM *next;
}Item;

typedef struct LIST
{
	Item *head;
	Item *end;
}List;

#define HASH_VAL 10

void insertItem(List* list, Item* item)
{
	int key = (unsigned int)item->val%HASH_VAL;
	if (!list[key].head)
	{
		list[key].head = item;
		list[key].end = item;
	}
	else
	{
		list[key].end->next = item;
		list[key].end = item;
	}
}

void showList(List* list)
{
	Item* p = NULL;
	for (int i = 0; i < 10; i++)
	{
		printf("%d:", i);
		p = list[i].head;
		if (p)
		{
			do
			{
				printf("%d(下标:%d)  ", p->val, p->index);
				if (p->next)
					p = p->next;
				else
					break;
			} while (1);
		}
		printf("\n");
	}
}

bool aaa(int* a, int val)
{
	for (int i = 0; i < 10; i++)
	{
		if (a[i] == val)
			return true;
	}
	return false;
}

bool serchItem(List* list, int val)
{
	int key = (unsigned int)val%HASH_VAL;
	Item* p = list[key].head;

	while (p)
	{
		if (p->val == val)
			return true;
		p = p->next;
	}
	return false;
}

int main(int argc, char* argv[])
{
	List list[10];
	Item item[10];
	memset(list, 0, sizeof(List)* 10);
	memset(item, 0, sizeof(Item)* 10);
	int a[10] = {21,11,1,51,5,6,7,8,9,0};

	for (int i = 0; i < 10; i++)
	{
		item[i].index = i;
		item[i].val = a[i];
		insertItem(list, &item[i]);
	}
	showList(list);
	system("pause");
	return 0;
}

  小博演示的拉链法是将数组的特点(方便查找,不易删除)以及链表的特点(方便删除,不易查找)取长补短的一种折中方法。

----------------------------------------------分界线,又出现了-----------------------------------------------------------------

文中好像很多废话,希望没有把各位大老爷给绕晕了,新人小白发表,不足之处请见谅,欢迎大牛指导,其他同道也可交流

如果不理解小博的思路,可以参考更详细的原理:http://www.cnblogs.com/tuhooo/p/7092288.html#3934840

原文地址:https://www.cnblogs.com/chen1026/p/8690578.html

时间: 2024-11-01 18:50:28

哈希表之拉链法的相关文章

【算法与数据结构】哈希表-链地址法

哈希表的链地址法来解决冲突问题 将所有关键字为同义词的记录存储在同一个线性链表中,假设某哈希函数产生的哈希地址在区间[0, m - 1]上,则设立一个至振兴向量 Chain  ChainHash[m]; 数据结构 //链表结点 typedef struct _tagNode { int data; //元素值(关键字) struct _tagNode* next; //下一个结点 }Node, *PNode; //哈希表结点 typedef struct _tagHashTable { //这里

哈希表(开链法)

纯代码 #pragma once #include <iostream> #include <vector> using namespace std; struct __HashFuncString { size_t operator()(const string &key) { size_t hash = 0; for (size_t i = 0; i < key.size(); ++i) { hash += key[i]; } return hash; } };

哈希表解决冲突法(二次探测)

故数据存储下标为 伪代码: 1. //index=_HashFunc(key); //++i; //index+=(2*i-1); size_t _HashFunc(const K& key) { return key%_capacity; } 2.//index=_HashFunc(key,++i); size_t _HashFunc(const K& key,size_t i) { return (key+i*i)%_capacity; } #pragma once #include&

poj 3349:Snowflake Snow Snowflakes(哈希查找,求和取余法+拉链法)

Snowflake Snow Snowflakes Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 30529   Accepted: 8033 Description You may have heard that no two snowflakes are alike. Your task is to write a program to determine whether this is really true. Y

深入理解哈希表

有两个字典,分别存有 100 条数据和 10000 条数据,如果用一个不存在的 key 去查找数据,在哪个字典中速度更快? 有些计算机常识的读者都会立刻回答: “一样快,底层都用了哈希表,查找的时间复杂度为 O(1)”.然而实际情况真的是这样么? 答案是否定的,存在少部分情况两者速度不一致,本文首先对哈希表做一个简短的总结,然后思考 Java 和 Redis 中对哈希表的实现,最后再得出结论,如果对某个话题已经很熟悉,可以直接跳到文章末尾的对比和总结部分. 哈希表概述 Objective-C 中

数据结构与算法分析:哈希表

以下是阅读了<算法导论>后,对哈希表的一些总结: 哈希表又叫散列表,是实现字典操作的一种有效数据结构.哈希表的查询效率极高,在没有冲突(后面会介绍)的情况下可做到一次存取便能得到所查记录,在理想情况下,查找一个元素的平均时间为O(1)(最差情况下散列表中查找一个元素的时间与链表中查找的时间相同:O(n),但实际情况中一般散列表的性能是比较好的). 哈希表就是描述key-value对的映射问题的数据结构,更详细的描述是:在记录的存储位置和它的关键字之间建立一个确定的对应关系h,使每个关键字与哈希

程序员,你应该知道的数据结构之哈希表

哈希表简介 哈希表也叫散列表,哈希表是一种数据结构,它提供了快速的插入操作和查找操作,无论哈希表总中有多少条数据,插入和查找的时间复杂度都是为O(1),因为哈希表的查找速度非常快,所以在很多程序中都有使用哈希表,例如拼音检查器. 哈希表也有自己的缺点,哈希表是基于数组的,我们知道数组创建后扩容成本比较高,所以当哈希表被填满时,性能下降的比较严重. 哈希表采用的是一种转换思想,其中一个中要的概念是如何将键或者关键字转换成数组下标?在哈希表中,这个过程有哈希函数来完成,但是并不是每个键或者关键字都需

哈希表——线性探测法、链地址法、查找成功、查找不成功的平均长度

一.哈希表 1.概念 哈希表(Hash Table)也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构.它通过把关键码值映射到哈希表中的一个位置来访问记录,以加快查找的速度.这个映射函数就做散列函数,存放记录的数组叫做散列表. 2.散列存储的基本思路 以数据中每个元素的关键字K为自变量,通过散列函数H(k)计算出函数值,以该函数值作为一块连续存储空间的的单元地址,将该元素存储到函数值对应的单元中. 3.哈希表查找的时间复杂度 哈希表存储的是键值对,其查找的时间复杂度与元素数

哈希表之开地址法解决冲突

在上一篇博文中,我们讲述了使用链地址法解决冲突的方法.这里我们介绍另一种方式:开地址法解决冲突. 基本思想:当关键码key的哈希地址H0 = hash(key)出现冲突时,以H0为基础,产生另一个哈希地址H1 ,如果H1仍然冲突,再以H0 为基础,产生另一个哈希地址H2 ,-,直到找出一个不冲突的哈希地址Hi ,将相应元素存入其中.根据增量序列的取值方式不同,相应的再散列方式也不同.主要有以下四种: 线性探测再散列 二次探测再散列 伪随机探测再散列 双散列法 (一)线性探测再散列 理解起来很简单