1. 程式人生 > >哈希表之拉鏈法

哈希表之拉鏈法

++ string def 點名 key 比較 並不是 數據結構 繼續

前段時間理解了一下所謂的哈希表,一直以來在小博印象中哈希表是深奧的,是高大上的,但是接觸原理以及看了一份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

哈希表之拉鏈法