[數據結構 - 第8章] 查找之哈希表(C語言實現)


首先是需要定義一個哈希表的結構以及一些相關的常數。其中 HashTable 就是哈希表結構。結構當中的 elem 為一個動態數組。

#define HASHSIZE 12 // 定義哈希表長為數組的長度
#define NULLKEY -32768 // 空關鍵碼

typedef struct
{
	int *elem; // 數據元素存儲基址,動態分配數組
	int count; //  當前數據元素個數
}HashTable;

int m = 0; // 哈希表表長,全局變量

一、哈希表基本操作

1.1 初始化操作

有了結構的定義,我們可以對哈希表進行初始化:

// 初始化哈希表
Status initHashTable(HashTable *H)
{
	int i;

	m = HASHSIZE;
	H->count = m;
	H->elem = (int *)malloc(m*sizeof(int));
	for (i = 0; i<m; i++)
		H->elem[i] = NULLKEY;

	return TRUE;
}

1.2 構造哈希函數操作

為了插入時計算地址,我們需要定義哈希函數,哈希函數可以根據不同情況更改算法。這里我們使用的構造方法為除留余數法

// 構造哈希函數
int hash(int key)
{
	return key % m; // 構造方法為除留余數法
}

1.3 插入關鍵字操作

初始化完成后,我們可以對哈希表進行插入操作。假設我們插入的關鍵字集合就是前面的 {12,67,56,16,25,37,22,29,15,47,48,34}。這里使用開放定址法來避免哈希沖突:

// 插入關鍵字進哈希表
void insertHash(HashTable *hash, int key)
{
	int addr = hashFun(key); // 求哈希地址
	while (hash->elem[addr] != NULLKEY) // 如果不為空,則沖突
	{
		addr = (addr + 1) % m; // 開放定址法的線性探測
	}
	hash->elem[addr] = key; // 直到有空位后插入關鍵字
}

1.4 查找關鍵字操作

哈希表存在后,我們在需要時就可以通過哈希表查找要的記錄。

// 哈希表查找關鍵字
Status searchHash(HashTable hash, int key, int *addr)
{
	*addr = hashFun(key); // 求哈希地址,如果后面的hash.elem[*addr] == key,則說明查找成功,直接返回
	while (hash.elem[*addr] != key) // 否則,使用開放定址法繼續查找
	{
		*addr = (*addr + 1) % m; // 開放定址法的線性探測
		// 如果 查找到NULLKEY | 循環回到原點,則說明關鍵字不存在,返回FALSE
		if (hash.elem[*addr] == NULLKEY || *addr == hashFun(key))
			return FALSE;
	}

	return TRUE;
}

可以看出,查找的代碼與插入的代碼非常類似,只需做一個不存在關鍵字的判斷而已。


二、完整程序

#include <stdio.h>
#include <stdlib.h>   

#define TRUE 1
#define FALSE 0

#define MAXSIZE 100 /* 存儲空間初始分配量 */

typedef int Status;	/* Status是函數的類型,其值是函數結果狀態代碼,如TRUE等 */

#define HASHSIZE 12 // 定義哈希表長為數組的長度
#define NULLKEY -32768 // 空關鍵字

typedef struct
{
	int *elem; // 數據元素存儲基址,動態分配數組
	int count; //  當前數據元素個數
}HashTable;

int m = 0; // 哈希表表長,全局變量

Status initHashTable(HashTable *hash); // 初始化哈希表
// 構造哈希函數
int hashFun(int key);

// 初始化哈希表
Status initHashTable(HashTable *hash)
{
	int i;

	m = HASHSIZE;
	hash->count = m;
	hash->elem = (int *)malloc(m*sizeof(int));
	for (i = 0; i<m; i++)
		hash->elem[i] = NULLKEY;

	return TRUE;
}

// 構造哈希函數
int hashFun(int key)
{
	return key % m; // 構造方法為除留余數法
}

// 插入關鍵字進哈希表
void insertHash(HashTable *hash, int key)
{
	int addr = hashFun(key); // 求哈希地址
	while (hash->elem[addr] != NULLKEY) // 如果不為空,則沖突
	{
		addr = (addr + 1) % m; // 開放定址法的線性探測
	}
	hash->elem[addr] = key; // 直到有空位后插入關鍵字
}

// 哈希表查找關鍵字
Status searchHash(HashTable hash, int key, int *addr)
{
	*addr = hashFun(key); // 求哈希地址,如果后面的hash.elem[*addr] == key,則說明查找成功,直接返回
	while (hash.elem[*addr] != key) // 否則,使用開放定址法繼續查找
	{
		*addr = (*addr + 1) % m; // 開放定址法的線性探測
		// 如果 查找到NULLKEY | 循環回到原點,則說明關鍵字不存在,返回FALSE
		if (hash.elem[*addr] == NULLKEY || *addr == hashFun(key))
			return FALSE;
	}

	return TRUE;
}

int main()
{
	int arr[HASHSIZE] = {12, 67, 56, 16, 25, 37, 22, 29, 15, 47, 48, 34}; // 要插入關鍵字
	int key = 39; // 關鍵字
	int addr; // 哈希地址
	HashTable hash;

	// 初始化哈希表
	initHashTable(&hash);

	// 插入關鍵字到哈希表
	for (int i = 0; i<m; i++)
		insertHash(&hash, arr[i]);

	// 查找Key為39的關鍵字(會失敗)
	int result = searchHash(hash, key, &addr);
	if (result)
		printf("查找 %d 的哈希地址為:%d \n\n", key, addr);
	else
		printf("查找 %d 失敗。\n\n", key);

	// 遍歷查找關鍵字(都會成功)
	
	for (int i = 0; i<m; i++)
	{
		key = arr[i];
		searchHash(hash, key, &addr);
		printf("查找 %d 的哈希地址為:%d \n", key, addr);
	}
	printf("\n");

	return 0;
}

輸出結果如下圖所示:


參考:

《大話數據結構 - 第8章》 查找



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM