數據結構_別問,問就是“哈希表”!!!

哈希表的故事導入

故事情節
爲了提高開發團隊精神,緩解工作壓力,某 IT 公司組織開發團隊的 12 位男同事和測試團隊 的 12 位女同事開展真人 CS 4vs4 野戰聯誼!面對性感的女同事,男同事們個個摩拳擦掌,躍躍欲 試!
在這裏插入圖片描述

野戰活動那天,根據男女搭配,幹活不累的原則,帶隊的專業教練讓男同事站成一排,女同 事站成一排,然後要求從女生這排開始從 1 開始報數,每個報數的隊員都要記住自己的編號: 1, 2, 3,4。。。。。。林子裏響起了百靈鳥般的報數聲!

報數時,教練發給每人一個白色的臂章貼在肩膀上,每個臂章上寫着報數人自己報過的編號!
在這裏插入圖片描述
通過這種編號方式劃分隊列,無論隊員歸隊,還是裁判確89認79隊43員8身40份1,11都1非常方便,此後林 子裏傳來隆隆的笑聲和槍炮聲!

這種編號的方式就是高效的散列,我們俗稱“哈希”!

以上過程是通過把關鍵碼值 key(編號)映射到表中一個位置(數組的下標)來訪問記錄,以加 快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表。

哈希表的原理

哈希表 - 散列表, 它是基於快速存儲的角度設計的, 也是一種典型 “空間換時間” 的做法

鍵(key): 組員的編號 如, 1, 5, 19 …
值(value): 組員的其他信息(包括 性別, 年齡和戰鬥力等)
索引: 數組的下表(0,1,2,3,4), 用以快速定位和檢索數據
哈希桶: 保存索引的數組(鏈表或數組), 數組成員爲每一個索引值相同的多個元素
哈希函數: 將組員編號映射到索引上, 採用求餘法, 如: 組員編號 19
在這裏插入圖片描述

哈希鏈表的算法實現

參考:

#include <iostream>

using namespace std;

#define DEFAULT_SIZE 16

typedef struct _ListNode
{
	struct _ListNode* next;
	int key;
	void* data;
}ListNode;

typedef ListNode* List;
typedef ListNode* element;

typedef struct _HashTable
{
	int TableSize; /* 哈希桶的數量 */
	List* Thelists; /* 指針數組 */
}HashTable;


int Hash(void* key, int TableSize); /* 哈希函數 */
HashTable* InitHash(int TableSize); /* 初始化哈希表 */
void Insert(HashTable* HashTable, int key, void* valuue); /* 哈希表插入 */
void Delete(HashTable* HashTable, int key); /* 哈希表刪除元素, 元素爲鍵值對 */
element Find(HashTable* HashTable, int key);/* 哈希表的查找 */
void* Retrieve(element e); /* 哈希表元素中提取數據 */
void Destory(HashTable* HashTable);/* 哈希表的銷燬 */


int Hash(int key, int TableSize)
{
	return (key % TableSize);
}

HashTable* InitHash(int TableSize)
{
	int i = 0;
	HashTable* hTable = NULL;

	if (TableSize <= 0)
	{
		TableSize = DEFAULT_SIZE;
	}

	hTable = (HashTable*)malloc(sizeof(HashTable));
	if (hTable == NULL)
	{
		printf("HashTable malloc error.\n");
		return NULL;
	}

	hTable->TableSize = TableSize;

	/* 爲Hash桶分配內存空間, 其爲一個指針數組 */
	hTable->Thelists = (List*)malloc(sizeof(List) * TableSize);
	if (hTable->Thelists == NULL)
	{
		printf("HashTable malloc error\n");
		free(hTable);
		return NULL;
	}

	/* 爲Hash 桶對應的指針數組初始化鏈表節點 */
	for (i = 0; i < TableSize; i++)
	{
		hTable->Thelists[i] = (ListNode*)malloc(sizeof(ListNode));
		if (hTable->Thelists[i] == NULL)
		{
			printf("HashTable malloc error\n");
			free(hTable->Thelists);
			free(hTable);
			return NULL;
		}
		else
		{
			memset(hTable->Thelists[i], 0, sizeof(ListNode));
		}
	}

	return hTable;
}

void Insert(HashTable* HashTable, int key, void* value)
{
	element e = NULL, tmp = NULL;
	List L = NULL;
	e = Find(HashTable, key);

	if (e == NULL)
	{
		tmp = (element)malloc(sizeof(ListNode));
		if (tmp == NULL)
		{
			printf("malloc error\n");
			return;
		}

		L = HashTable->Thelists[Hash(key, HashTable->TableSize)];
		tmp->data = value;
		tmp->key = key;
		tmp->next = L->next;
		L->next = tmp;
	}
	else
	{
		printf("the key already exist\n");
	}
}

void Delete(HashTable* HashTable, int key)
{
	element e = NULL, last = NULL;
	List L = NULL;
	int i = Hash(key, HashTable->TableSize);
	L = HashTable->Thelists[i];

	last = L;
	e = L->next;
	while (e != NULL && e->key != key)
	{
		last = e;
		e = e->next;
	}

	if (e) /* 如果鍵值存在 */
	{
		last->next = e->next;
		delete(e);
	}
}

element Find(HashTable* HashTable, int key)
{
	int i = 0;
	List L = NULL;
	element e = NULL;
	i = Hash(key, HashTable->TableSize);
	L = HashTable->Thelists[i];
	e = L->next;
	while (e != NULL && e->key != key)
	{
		e = e->next;
	}

	return e;
}

void* Retrieve(element e)
{
	return e ? e->data : NULL;
}

void Destory(HashTable* HashTable)
{
	int i = 0;
	List L = NULL;
	element cur = NULL, next = NULL;
	for (i = 0; i < HashTable->TableSize; i++)
	{
		L = HashTable->Thelists[i];
		cur = L->next;
		while (cur != NULL)
		{
			next = cur->next;
			free(cur);
			cur = next;
		}
		free(L);
	}
	free(HashTable->Thelists);
	free(HashTable);
}

int main()
{
	const char* elems[] = { "翠花","小芳","蒼老師" };
	int i = 0;

	HashTable* HashTable;
	HashTable = InitHash(31);
	Insert(HashTable, 1, (char *)elems[0]);
	Insert(HashTable, 2, (char*)elems[1]);
	Insert(HashTable, 3, (char*)elems[2]);
	
	Delete(HashTable, 1);

	for (i = 0; i < 4; i++)
	{
		element e = Find(HashTable, i);
		if (e)
		{
			printf("%s\n", (const char*)Retrieve(e));
		}
		else
		{
			printf("Not found [key:%d]\n", i);
		}
	}

	system("pause");
	return 0;
}

運行環境: vs2019
運行結果:
在這裏插入圖片描述

結語:

學到的知識要, 多複習, 多總結, 多敲. 需要時間的積累, 才能引起質的改變. 自己寫不出來的永遠是別人的.

分享一下我的技巧: 代數法把具體的數字帶進去, 看看能能能找到規律(掌握思想).
還有就是畫圖, 也很重要. 用筆畫出來, 把數代進去, 方法雖然笨, 但真的很實用, 好記憶不如爛筆頭!!! 還有多用debug(調試工具)

我是小白, C/C++功力…, 你懂得, 寫的文章可能不是很好. 如果存在問題, 歡迎大神給予評判指正.
錯了不可怕, 可怕的是找不出bug, 誰沒錯過!!!

最近學操作系統我認爲, 學什麼都要成本(時間), 即使它是免費的, 我個人認爲要挑來學, 挑重點來學, 而不是從頭到尾, 除非考試考研.

這個知識點我沒有完全掌握, 就是會了也要複習, 革命尚未成功, 同志還需努力!!! , 我會回來反覆複習的

今日是: 2020年5月21日, (由於疫情的原因)現在沒有返校. 寫博客,也可自己加強記憶,就當寫寫日記吧!!!

希望給個贊: 反正你又不虧, 順便而已

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章