1. 程式人生 > >c實現雜湊查詢

c實現雜湊查詢

雜湊查詢,也稱為雜湊查詢(本文以雜湊稱呼)。雜湊它是由一組key/value的鍵值對組成的集合,它就是應用了雜湊技術。

那麼,什麼是雜湊查詢呢?在弄清楚什麼是雜湊查詢之前,我們要弄清楚雜湊技術,雜湊技術是在記錄的儲存位置和記錄的關鍵字之間建立一個確定的對應關係f,使得每個關鍵字key對應一個儲存位置f(key)。查詢時,根據這個確定的對應關係找到給定值的對映f(key),若查詢集合中存在這個記錄,則必定在f(key)的位置上。雜湊技術既是一種儲存方法,也是一種查詢方法。

六種雜湊函式的構造方法:

1,直接定址法:

函式公式:f(key)=a*key+b (a,b為常數)

這種方法的優點是:簡單,均勻,不會產生衝突。但是需要事先知道關鍵字的分佈情況,適合查詢表較小並且連續的情況。

2,數字分析法:

比如我們的11位手機號碼“136XXXX7887”,其中前三位是接入號,一般對應不同運營公司的子品牌,如130是聯通如意通,136是移動神州行,153是電信等。中間四們是HLR識別號,表示使用者歸屬地。最後四們才是真正的使用者號。

若我們現在要儲存某家公司員工登記表,如果用手機號碼作為關鍵字,那麼極有可能前7位都是相同的,所以我們選擇後面的四們作為雜湊地址就是不錯的選擇。

3,平方取中法:

故名思義,比如關鍵字是1234,那麼它的平方就是1522756,再抽取中間的3位就是227作為雜湊地址。

4,摺疊法:

摺疊法是將關鍵字從左到右分割成位數相等的幾個部分(最後一部分位數不夠可以短些),然後將這幾部分疊加求和,並按雜湊表表長,取後幾位作為雜湊地址。

比如我們的關鍵字是9876543210,雜湊表表長三位,我們將它分為四組,987|654|321|0 ,然後將它們疊加求和987+654+321+0=1962,再求後3位即得到雜湊地址為962,哈哈,是不是很有意思。

5,除留餘數法:

函式公式:f(key)=key mod p (p<=m)m為雜湊表表長。

這種方法是最常用的雜湊函式構造方法。

6,隨機數法:

函式公式:f(key)= random(key)。

這裡random是隨機函式,當關鍵字的長度不等是,採用這種方法比較合適。

兩種雜湊函式衝突解決方法:

我們設計得最好的雜湊函式也不可能完全避免衝突,當我們在使用雜湊函式後發現兩個關鍵字key1!=key2,但是卻有f(key1)=f(key2),即發生衝突。

方法一:開放定址法:

開放定址法就是一旦發生了衝突,就去尋找下一個空的雜湊地址,只要雜湊表足夠大,空的雜湊地址總是能找到,然後將記錄插入。這種方法是最常用的解決衝突的方法。

方法二:鏈地址法:

//採用除數取留法確定地址,利用線性開放地址法處理衝突問題,2016.5.28
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <math.h>
#include<time.h>

#define HASHSIZE 15
#define NULLKEY -32768

typedef struct
{
	int *elem; //資料元素儲存地址
	int count;//當前元素個數
}HashTable;
int L = 0; //表的長度

bool init(HashTable *hashTable)//雜湊表的初始化
{
	int i;
	L = HASHSIZE;
	hashTable->elem = (int*)malloc(L*sizeof(int));//申請記憶體
	hashTable->count = L;
	for (i = 0; i < L; i++)
	{
		hashTable->elem[i]=NULLKEY;
	}
	return true;
}

//雜湊函式,除留餘數法,最常用的雜湊函式,還有其它的。
int Hash(int data)
{
	return data%L;
}

void insert( HashTable *hashTable, int data)
{
	int Addr = Hash(data);//求雜湊地址
	while (hashTable->elem[Addr] != NULLKEY)//求得地址不是初始化時的空,則表示有元素已經插入,會有衝突
	{
		Addr = (Addr + 1) % L;//開放地址線性探測,還可以二次探測
	}
	hashTable->elem[Addr] = data;
}

int  find(HashTable *hashTable, int data)
{
	int Addr = Hash(data);
	while (hashTable->elem[Addr] != data)
	{
		Addr = (Addr + 1) % L;
		if (hashTable->elem[Addr] == NULLKEY || Addr == Hash(data))
			return 0;
	}
	return Addr;
}

void display(HashTable *hashTable)
{
	int i;
	printf(".........結果展示.........\n");
	for (i = 0; i < hashTable->count; i++)
	{
		printf("%d\n", hashTable->elem[i]);
	}
}

void main()
{
	int i, j, result, x;
	HashTable hashTable;
	int arr[HASHSIZE];
	printf("請輸入少於15個,初始化雜湊表的元素:\n");
	for (j = 0; j < HASHSIZE; j++)
	{
		scanf("%d", &arr[j]);
	}
	init(&hashTable);
	for (i = 0; i < HASHSIZE; i++)
	{
		insert(&hashTable, arr[i]);
	}
	display(&hashTable);
	printf("請輸入你要查詢的元素:\n");
	scanf("%d", &x);
	result = find(&hashTable, x);
	if (result)
		printf("查詢元素%d在雜湊表中的位置為%d\n",x,result);
	else 
		printf("沒找到!\n");
	system("pause");
}