数据结构与算法(C)—散列表

本文变量命名前缀:

  1. 全局变量:g_
  2. 数组:a
  3. 指针:p
  4. 结构体:st
  5. unsigned int:ui

本文代码可以到Github下载:https://github.com/liyuewu-github/DataStructure

一、HASH数据结构定义

需要定义HASH冲突域。HASH TABLE中增加HASH算法和排序算法,增强HASA TABLE可用性。

/* HASH冲突域链表节点 */
typedef struct tagHASH_LIST
{
	unsigned int uiValue;
	struct tagHASH_LIST *pHashList;
}HASH_LIST_S;

/* HASH表 */
typedef struct tagHASH_TABLE
{
	unsigned int uiTableSize;  /* HASH表大小  */
	unsigned int (*pFunHash)(const void *);     /* HASH算法  */
	unsigned int (*pFunCmp)(unsigned int uiKey, unsigned int uiOldKey);    /* HASH冲突域值比较  */
	HASH_LIST_S **ppHashList;     /* HASH数组链表    */
}HASH_TABLE_S;

二、HASH表创建

HASH表创建,指定HASA表长度。

/* HASH表创建 */
HASH_TABLE_S * HASH_Create(
	IN unsigned int uiTableSize, 
	IN unsigned int (*pFunHash)(const void *), 
	IN unsigned int (*pFunCmp)(unsigned int uiKey, unsigned int uiOldKey))
{
	HASH_TABLE_S *pstHashTable;
	unsigned int i;

	pstHashTable = malloc(sizeof(HASH_TABLE_S));
	if (NULL == pstHashTable)
	{
		return NULL;
	}

	pstHashTable->ppHashList = malloc(sizeof(HASH_LIST_S) * uiTableSize);
	if (NULL == pstHashTable->ppHashList)
	{
		free(pstHashTable);
		return NULL;
	}
	memset(pstHashTable->ppHashList, 0, sizeof(HASH_LIST_S) * uiTableSize);
	pstHashTable->uiTableSize = uiTableSize;
	pstHashTable->pFunHash = pFunHash;
	pstHashTable->pFunCmp = pFunCmp;

	return pstHashTable;
}

三、HASH表插入

HASH表插入使用HASH算法找到index,再根据比较算法找到插入的位置。实现了HASH冲突域有序排列。

/* HASH表插入 */
unsigned int HASH_Insert( IN HASH_TABLE_S *pstHashTable, IN unsigned int uiKey)
{
	HASH_LIST_S *pstHashFind;
	HASH_LIST_S *pstNewHashNode;
	HASH_LIST_S *pstHashCmp;
	unsigned int uiHashIndex;

	pstHashFind = HASH_Find(pstHashTable, uiKey);
	if (NULL == pstHashFind)
	{
		pstNewHashNode = malloc(sizeof(HASH_LIST_S));
		if (NULL == pstNewHashNode)
		{
			return HASH_NOMEM;
		}
		uiHashIndex = pstHashTable->pFunHash((void *)&uiKey);
		pstNewHashNode->uiValue = uiKey;

		pstHashCmp = pstHashTable->ppHashList[uiHashIndex];

		while(pstHashCmp)
		{
			if (pstHashTable->pFunCmp(uiKey, pstHashCmp->uiValue ))
			{
				break;
			}
			pstHashCmp = pstHashCmp->pHashList;
		}
		
		if (NULL == pstHashCmp) /* 当前节点为冲突域中的最大值或者最小值 */
		{
			pstNewHashNode->pHashList = pstHashTable->ppHashList[uiHashIndex];
			pstHashTable->ppHashList[uiHashIndex] = pstNewHashNode;
		}
		else  /* 当前节点为冲突域中的中间值,插入pstHashCmp之后 */
		{
			pstNewHashNode->pHashList = pstHashCmp->pHashList;
			pstHashCmp->pHashList = pstNewHashNode;
		}
		#ifdef HASH_TRACE
		printf("Key %d index %d head %p node %p nextnode %p\n",uiKey, uiHashIndex,
			pstHashTable->ppHashList[uiHashIndex],pstNewHashNode, pstNewHashNode->pHashList);
		#endif
	}
	#ifdef HASH_TRACE
	else
	{
		printf("The Key %d is repect\n",uiKey);
	}
	#endif
	return HASH_OK;
}

四、HASH表查找

HASH查找需要遍历冲突域查找。这是一般的查找方法,对于实现了冲突域排序的HASH表,可以使用二分法查找。

/* HASH表查找 */
HASH_LIST_S *HASH_Find( IN HASH_TABLE_S *pstHashTable, IN unsigned int uiKey)
{
	HASH_LIST_S *pstHashFind;
	unsigned int uiHashIndex;

	uiHashIndex = pstHashTable->pFunHash((void *)&uiKey);
	pstHashFind = pstHashTable->ppHashList[uiHashIndex];

	while(pstHashFind)
	{
		if(pstHashFind->uiValue == uiKey)
		{
			break;
		}
		pstHashFind = pstHashFind->pHashList;
	}

	return pstHashFind;
}

五、HASH表删除

/* HASH表删除 */
void HASH_Destroy(IN HASH_TABLE_S * pstHashTable)
{
	HASH_LIST_S *pstHashScan;
	unsigned int uiHashIndex;

	for (uiHashIndex = 0; uiHashIndex < pstHashTable->uiTableSize; uiHashIndex++)
	{
		pstHashScan = pstHashTable->ppHashList[uiHashIndex];

		while(pstHashScan)
		{
			free(pstHashScan);
			pstHashScan = pstHashScan->pHashList;
		}
	}
	free(pstHashTable->ppHashList);
	free(pstHashTable);
	return;
}

六、HASH表打印

/* HASH表打印 */
unsigned int HASH_Dump( IN HASH_TABLE_S *pstHashTable )
{
	HASH_LIST_S *pstHashScan;
	unsigned int uiHashIndex;
	char * pcBuf;
	unsigned int uiLen = 0;

	pcBuf = (char * )malloc(HASH_BUFLEN);
	if (NULL == pcBuf)
	{
		return HASH_NOMEM;
	}

	for (uiHashIndex = 0; uiHashIndex < pstHashTable->uiTableSize; uiHashIndex++)
	{
		uiLen += snprintf((pcBuf+uiLen), (HASH_BUFLEN-uiLen), "----------------HASH INDEX %u----------------\n", uiHashIndex);
		pstHashScan = pstHashTable->ppHashList[uiHashIndex];

		while(pstHashScan)
		{
			uiLen += snprintf((pcBuf+uiLen), (HASH_BUFLEN-uiLen), "node %p value %u\n", pstHashScan, pstHashScan->uiValue);
			pstHashScan = pstHashScan->pHashList;
		}
	}

	printf("%s", pcBuf);
	free(pcBuf);
}

七、测试程序

100个数字0-99, 放到hash地址为0-19的hash表中, hash函数为key/5。将冲突值按大小顺序排列放入冲突域链表。

#define __TEST_PROCESS__

#define HASHTEST_MOD   5
#define HASHTEST_SIZE  20

unsigned int HASH(const void * pKey)
{
	return (*(unsigned int *)pKey/HASHTEST_MOD);
}

unsigned int Cmp(unsigned int uiKey, unsigned int uiOldKey)
{
	return (uiKey < uiOldKey ? 1 : 0);
}

void main()
{
	HASH_TABLE_S * pstHashTest;
	int i;
	pstHashTest = HASH_Create(HASHTEST_SIZE, HASH,Cmp);
	if (NULL == pstHashTest)
	{
		return;
	}
	for (i=0;i<100;i++)
		HASH_Insert(pstHashTest, i);

	HASH_Insert(pstHashTest, 17);
	HASH_Insert(pstHashTest, 15);
	HASH_Insert(pstHashTest, 16);

	HASH_Dump(pstHashTest);
	HASH_Destroy(pstHashTest);
	return;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值