前段时间理解了一下所谓的哈希表,一直以来在小博印象中哈希表是深奥的,是高大上的,但是接触原理以及看了一份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