鏈式哈希表

鏈式哈希表介紹

        待補充


鏈式哈希表實現

// Chtbl.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>


/*鏈表元素結構體定義*/
typedef struct ListElmt_
{
	void *pdata;
	struct ListElmt_ *pNext;
}ListElmt;

/*鏈表結構體定義*/
typedef struct List_
{
	int iSize;
	void (*destory)(void *data);
	ListElmt *ListElmtHead;
	ListElmt *ListElmtTail;
}List;

/*鏈表操作宏定義*/
#define LIST_SIZE(list) ((list)->iSize)
#define LIST_HEAD(list) ((list)->ListElmtHead)
#define LIST_TAIL(list) ((list)->ListElmtTail)
#define LIST_IS_HEAD(list, element) ((element == (list)->ListElmtHead) ? 1:0)
#define LIST_IS_TAIL(list, element) ((element == (list)->ListElmtTail) ? 1:0)
#define LIST_DATA(element) ((element)->pdata)
#define LIST_NEXT(element) ((element)->pNext)

/*
*函數名:List_Init
*參數:list  鏈表
*      destory  釋放鏈表節點內存的函數
*功能:單鏈表初始化
*返回值:無
*作者:AlbertoNo1
*日期:2016-04-14
*/
void List_Init(List *list, void (*destory)(void *data))
{
	/*入參合法性由調用者保證*/

	list->iSize = 0;
	list->destory = destory;
	list->ListElmtHead = NULL;
	list->ListElmtTail = NULL;

	return ;
}

/*
*函數名:List_Ins_Next
*參數:list  鏈表
*      Element  待插入元素的前一個節點元素
*      data     待插入元素數據
*功能:單鏈表添加節點函數
*返回值:0 成功  -1 失敗
*作者:AlbertoNo1
*日期:2016-04-14
*/
int List_Ins_Next(List *list, ListElmt *Element, void *data)
{
	ListElmt *Lelmt = NULL;

	if ((NULL == list) || (NULL == data))
	{
		return -1;
	}

	/*申請鏈表節點內存*/
	Lelmt = (ListElmt*)malloc(sizeof(ListElmt));
	if (NULL == Lelmt)
	{
		return -1;
	}

	Lelmt->pdata = data;

	if (NULL == Element)
	{
		/*在鏈表頭插入元素*/
		Lelmt->pNext = list->ListElmtHead;
		list->ListElmtHead = Lelmt;

		if (0 == LIST_SIZE(list))
		{
			list->ListElmtTail = Lelmt;
		}
	}
	else
	{
		/*在非鏈表頭插入元素*/
		Lelmt->pNext = Element->pNext;
		Element->pNext = Lelmt;

		if (NULL == Lelmt->pNext)
		{
			list->ListElmtTail = Lelmt;
		}
	}

	/*鏈表大小加1*/
	list->iSize++;

	return 0;
}

/*
*函數名:List_Rem_Next
*參數:list  鏈表
*      Element  待刪除元素的前一個節點元素
*      data     返回刪除元素的數據域
*功能:單鏈表刪除節點函數
*返回值:0 成功  -1 失敗
*作者:AlbertoNo1
*日期:2016-04-14
*/
int List_Rem_Next(List *list, ListElmt *Element, void **data)
{
	ListElmt *Old_Lelmt = NULL;

	if ((NULL == list) || (NULL == data))
	{
		return -1;
	}

	if (0 == LIST_SIZE(list))
	{
		return -1;
	}

	if (NULL == Element)
	{
		/*刪除鏈表頭元素*/
		*data = list->ListElmtHead->pdata;
		Old_Lelmt = list->ListElmtHead;
		list->ListElmtHead = list->ListElmtHead->pNext;

		if (1 == LIST_SIZE(list))
		{
			list->ListElmtTail = NULL;
		}

	}
	else
	{
		/*刪除非鏈表頭元素*/
		if (1 == LIST_SIZE(list))
		{
			return -1;
		}
		else
		{
			*data = Element->pNext->pdata;
			Old_Lelmt = Element->pNext;
			Element->pNext = Element->pNext->pNext;

			if (NULL == Element->pNext)
			{
				list->ListElmtTail = Element;
			}
		}
	}

	/*釋放刪除節點的內存*/
	free(Old_Lelmt);

	/*鏈表大小減一*/
	list->iSize--;

	return 0;
}

/*
*函數名:List_Destory
*參數:list  鏈表
*功能:單鏈表銷燬
*返回值:無
*作者:AlbertoNo1
*日期:2016-04-14
*/
void List_Destory(List *list)
{
	void *data = NULL;

	/*入參合法性由調用者保證*/

	while (LIST_SIZE(list) > 0)
	{
		if ((0 == List_Rem_Next(list, NULL, &data))&&(NULL != list->destory))
		{
			list->destory(data);
		}
	}

	memset(list, 0, sizeof(List));

	return ;
}

/*
*函數名:destory
*參數:data  動態申請內存的地址
*功能:釋放動態申請內存函數
*返回值:無
*作者:AlbertoNo1
*日期:2016-04-14
*/
void destory(void *data)
{
	free(data);
}

/*鏈式哈希表數據結構*/
typedef struct CHTbl_
{
	int buckets;  /*桶的個數*/

	int (*hash_func)(const void *key);
	int (*match)(const void *key1, const void *key2);
	void (*destroy)(void *data);

	int size;
	List *table;

}CHTbl;

/*鏈式哈希表操作宏定義*/
#define chtbl_size(htbl) ((htbl)->size)
#define CHTBL_BUCKETS   (100)

/*
*函數名:chtbl_hash
*參數:key  哈希鍵值
*功能:哈希函數
*返回值:哈希值
*作者:AlbertoNo1
*日期:2016-04-14
*/
int chtbl_hash(const void *key)
{
	int value = *((int*)key);

	return value%CHTBL_BUCKETS;
}

/*
*函數名:chtbl_match
*參數:pKey1  指向第一個比較元素的地址
*      pKey2  指向第二個比較元素的地址
*功能:比較兩個元素的大小
*返回值:1 表示Key1 大於 Key2
*        -1 表示Key1 小於 Key2
*        0 表示Key1 等於 Key2
*作者:AlbertoNo1
*日期:2016-04-14
*/
int chtbl_match(const void *pKey1, const void *pKey2)
{
	/*對兩個整型數進行比較*/
	if (*((int*)pKey1) > *((int*)pKey2))
	{
		return 1;
	}
	else if (*((int*)pKey1) < *((int*)pKey2))
	{
		return -1;
	}
	else
	{
		return 0;
	}
}

/*
*函數名:chtbl_init
*參數:htbl  鏈式哈希表
*      buckets  哈希表桶個數
*      h_func   哈希函數
*      m_func   元素比較函數
*      d_func   元素動態申請內存釋放函數
*功能:鏈式哈希表初始化函數
*返回值:0 成功  -1 失敗
*作者:AlbertoNo1
*日期:2016-04-14
*/
int chtbl_init(CHTbl *htbl, int buckets, int (*h_func)(const void *key),int (*m_func)(const void *key1, const void *key2),
	            void (*d_func)(void *data))
{
	int i = 0;

	/*爲哈希表申請內存空間*/
	htbl->table = (List*)malloc(buckets*sizeof(List));
	if (NULL == htbl->table)
	{
		return -1;
	}

	/*初始化(鏈表)桶*/
	htbl->buckets = buckets;
	for (i = 0; i < buckets; i++)
	{
		List_Init(&(htbl->table[i]), destory);
	}

	htbl->hash_func = h_func;
	htbl->match = m_func;
	htbl->destroy = d_func;

	htbl->size = 0;

	return 0;
}

/*
*函數名:chtbl_destory
*參數:htbl  鏈式哈希表
*功能:鏈式哈希表銷燬函數
*返回值:無
*作者:AlbertoNo1
*日期:2016-04-14
*/
void chtbl_destory(CHTbl *htbl)
{
	int i = 0;

	/*銷燬(鏈表)桶*/
	for (i = 0; i < htbl->buckets; i++)
	{
		List_Destory(&(htbl->table[i]));
	}

	/*釋放哈希表內存*/
	free(htbl->table);

	memset(htbl, 0, sizeof(CHTbl));

	return ;
}

/*
*函數名:chtbl_lookup
*參數:htbl  鏈式哈希表
*      data  待查找元素數據
*功能:鏈式哈希表元素查找函數
*返回值:0 哈希表中存在此元素  -1 哈希表中不存在此元素
*作者:AlbertoNo1
*日期:2016-04-14
*/
int chtbl_lookup(const CHTbl *htbl, void **data)
{
	ListElmt  *element = NULL;
	int   bucket = 0;

	/*獲得哈希值*/
	bucket = htbl->hash_func(*data)%(htbl->buckets);


	/*在(鏈表)桶中查找元素*/
	for (element = LIST_HEAD(&(htbl->table[bucket])); element != NULL; element = LIST_NEXT(element))
	{
		if (htbl->match(*data, LIST_DATA(element)) == 0)
		{/*找到該元素*/
			*data = LIST_DATA(element);
			return 0;
		}
	}

	/*該元素未找到*/
	return -1;
}

/*
*函數名:chtbl_insert
*參數:htbl  鏈式哈希表
*      data  待插入桶中的元素
*功能:鏈式哈希表添加元素函數
*返回值:0 成功  1 失敗
*作者:AlbertoNo1
*日期:2016-04-14
*/
int chtbl_insert(CHTbl *htbl, const void *data)
{
	void *temp = NULL;

	int bucket = 0;
	int retval = 0;

	/*如果哈希表中已經存在該元素,直接返回*/
	temp = (void*)data;
	if (chtbl_lookup(htbl, &temp) == 0)
	{
		return 1;
	}

	/*獲得哈希值*/
	bucket = htbl->hash_func(data)%(htbl->buckets);

	/*把元素插到對應的桶中*/
	retval = List_Ins_Next(&(htbl->table[bucket]), NULL, (void*)data);
	if (0 == retval)
	{/*插入成功*/
		htbl->size++;
	}

	return retval;
}

/*
*函數名:chtbl_remove
*參數:htbl  鏈式哈希表
*      data  待從桶中刪除的元素
*功能:鏈式哈希表刪除元素函數
*返回值:0 成功  -1 失敗
*作者:AlbertoNo1
*日期:2016-04-14
*/
int chtbl_remove(CHTbl *htbl, const void **data)
{
	ListElmt  *element = NULL;
    ListElmt  *prev = NULL;
	int   bucket = 0;  

	/*獲得哈希值*/
	bucket = htbl->hash_func(*data)%(htbl->buckets);

	/*在對應的鏈表桶中查找該元素*/
	for (element = LIST_HEAD(&(htbl->table[bucket])); element != NULL; element = LIST_NEXT(element))
	{
		if (htbl->match(*data, LIST_DATA(element)) == 0)
		{/*找到該元素*/
			/*從(鏈表)桶中移除該元素*/
			if (List_Rem_Next(&(htbl->table[bucket]), prev, (void**)data) == 0)
			{
				htbl->size--;
				return 0;
			}
			else
			{
				return -1;
			}
		}

		prev = element;
	}

	/*哈希表中不存在想要刪除的元素*/
	return -1;
}


int _tmain(int argc, _TCHAR* argv[])
{
	int iRet = 0;
	int iLoop = 0;
	int *piData = NULL;

	CHTbl stCHtbl = {0};

	chtbl_init(&stCHtbl, CHTBL_BUCKETS, chtbl_hash, chtbl_match, destory);

	for (iLoop = 0; iLoop < 10; iLoop++)
	{
		piData = (int*)malloc(sizeof(int));
		*piData = iLoop;
		iRet |= chtbl_insert(&stCHtbl,(void*)piData);
	}

	if (0 != iRet)
	{
		return -1;
	}

	piData = (int*)malloc(sizeof(int));
	*piData = 9;

	iRet = chtbl_lookup(&stCHtbl, (void**)&piData);

	printf("%d \r\n", iRet);

	free(piData);

	piData = (int*)malloc(sizeof(int));
	*piData = 10;

	iRet = chtbl_lookup(&stCHtbl, (void**)&piData);

	printf("%d \r\n", iRet);

	free(piData);

	piData = (int*)malloc(sizeof(int));
	*piData = 9;

	iRet = chtbl_remove(&stCHtbl, (const void**)&piData);

	printf("%d \r\n", iRet);

	free(piData);

	piData = (int*)malloc(sizeof(int));
	*piData = 9;

	iRet = chtbl_lookup(&stCHtbl, (void**)&piData);

	printf("%d \r\n", iRet);

	free(piData);

	chtbl_destory(&stCHtbl);

	getchar();
	return 0;
}


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