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