1. 程式人生 > >hash實現--開放定址方式

hash實現--開放定址方式

原文:http://blog.csdn.net/aa2010aa/article/details/4908113

今天看了一下《演算法導論》第十一章的散列表,裡面有一節是關於開發定址方式。


  下面是我的簡單的實現:

static const int __stl_num_primes = 28;
static const unsigned long __stl_prime_list[__stl_num_primes] =
{
  53,         97,           193,         389,       769,
  1543,       3079,         6151,        12289,     24593,
  49157,      98317,        196613,      393241,    786433,
  1572869,    3145739,      6291469,     12582917,  25165843,
  50331653,   100663319,    201326611,   402653189, 805306457, 
  1610612741, 3221225473ul, 4294967291ul
};
unsigned int m = __stl_prime_list[0];

int Hash_Key(int key)
{
	return key % m;
}

int Hash_Key1(int key)
{
	return 1 + key % (m-1);
}
/* int Hash_Key(int key, int i)
{
	return (Hash_Key(key) + i) % m;
} */

int Hash_Key(int key, int i)
{
	return (Hash_Key(key) + i * Hash_Key1(key)) % m;
}

int Hash_Create(int *&hashTable)
{
	if(0 == m)
	{
		hashTable = NULL;
		return -1;
	}
	hashTable = new int[m];
	if (NULL == hashTable)
	{
		return -1;
	}
	for(unsigned int i = 0; i < m; i++)
		hashTable[i] = -1;
	return 1;
}

int Hash_Insert(int *hashTable, int value)
{
	int key = Hash_Key(value, 0);
	for(unsigned int i = 1; i < m; i++)
	{
		if (-1 == hashTable[key])
		{
			hashTable[key] = value;
			return key;
		}
		key = Hash_Key(value, i);
	}
	return -1;
}

int Hash_Find(int *hashTable, int value)
{
	int key = Hash_Key(value, 0);
	for(unsigned int i = 1; i < m; i++)
	{
		if(-1 == hashTable[key])
		{
			return -1;
		}
		if(value == hashTable[key])
		{
			return key;
		}
		key = Hash_Key(value, i);
	}
	return -1;
}

void Hash_Delete(int *hashTable)
{
	delete []hashTable;
}

 下面是測試:
int main()
{
	srand(time(NULL));
	unsigned int k;
	unsigned int i;
	clock_t begin, finish;
	cin >> k;
	for(i = 0; i < __stl_num_primes && k > __stl_prime_list[i]; i++);
		m = __stl_prime_list[i];
	int  *hap;
	try
	{
		Hash_Create(hap);
	}
	catch(bad_alloc &e)
	{
		cout << "create wrong" << endl;
		return -1;
	}
	begin = clock();
	for(unsigned int i = 0; i < m / 10; i++)
	{
		int d = Random32()%m;
		if( -1  == Hash_Insert(hap, d))
		{
			cout << "insert wrong" << endl;
		}
	}
	finish = clock();
	cout << "insert time";
	cout << (double)(finish - begin)/CLOCKS_PER_SEC << endl;
	begin = clock();
	for(unsigned int i = 0; i < m / 10; i++)
	{
		int d = Random32()%m;
		if( -1  == Hash_Find(hap, d))
		{
			//cout << d << "  find wrong" << endl;
		}
	}
	finish = clock();
	cout << (double)(finish - begin)/CLOCKS_PER_SEC << endl;
	Hash_Delete(hap); 
}
其中的Random32()的實現是:
unsigned int Random32(void) {   
      
    static const unsigned long x[55] = {   
      1410651636UL, 3012776752UL, 3497475623UL, 2892145026UL, 1571949714UL,   
      3253082284UL, 3489895018UL, 387949491UL, 2597396737UL, 1981903553UL,   
      3160251843UL, 129444464UL, 1851443344UL, 4156445905UL, 224604922UL,   
      1455067070UL, 3953493484UL, 1460937157UL, 2528362617UL, 317430674UL,   
      3229354360UL, 117491133UL, 832845075UL, 1961600170UL, 1321557429UL,   
      747750121UL, 545747446UL, 810476036UL, 503334515UL, 4088144633UL,   
      2824216555UL, 3738252341UL, 3493754131UL, 3672533954UL, 29494241UL,   
      1180928407UL, 4213624418UL, 33062851UL, 3221315737UL, 1145213552UL,   
      2957984897UL, 4078668503UL, 2262661702UL, 65478801UL, 2527208841UL,   
      1960622036UL, 315685891UL, 1196037864UL, 804614524UL, 1421733266UL,   
      2017105031UL, 3882325900UL, 810735053UL, 384606609UL, 2393861397UL };   
    static int init = 1;   
    static unsigned long y[55];   
    static int j, k;   
    unsigned long ul;   
    
    if (init)   
    {   
      int i;   
      
      init = 0;   
      for (i = 0; i < 55; i++) y[i] = x[i];   
      j = 24 - 1;   
      k = 55 - 1;   
    }   
    
    ul = (y[k] += y[j]);   
    if (--j < 0) j = 55 - 1;   
    if (--k < 0) k = 55 - 1;   
    return((unsigned int)ul);   
}  

 c函式rand()產生的數在0~RAND_MAX之間(在我的機器,RAND_MAX的大小是32767),比較小,不利於測試,Random32函式

能產生0到unsigned int最大之間的數。

   開放定址的方式相對連結串列方式節省了空間(省了一個指標),但加大了插入和查詢時間,特別如果插入的數重複太多的話,那麼時間會有一個很大的提升。

   下面是測試結果:

   

  如果用rand代替Random32,測試結果是:

  

  當到了10000000,對比一下就知道,那時間是花花的上去了。


相關推薦

hash實現--開放方式

原文:http://blog.csdn.net/aa2010aa/article/details/4908113 今天看了一下《演算法導論》第十一章的散列表,裡面有一節是關於開發定址方式。   下面是我的簡單的實現: static const int __stl_num_p

C語言 開放HASH表儲存簡單實現

#include<stdio.h> #include<stdlib.h> #include<malloc.h> #include<string.h> #include<time.h> #include<cty

Atitit 計算機系統結構 計算機系統結構 Cpu 儲存 cache 指令系統 目錄 Line 56: 第2章指令系統設計 指令格式 方式 1 Line 64: 第3章CPU及其實現

Atitit 計算機系統結構  計算機系統結構   Cpu  儲存 cache   指令系統 目錄 Line 56: 第2章指令系統設計 指令格式  定址方式 1 Line 64: 第3章CPU及其實

[資料結構]Hash表初學(開放法 )

/* Name:Hash表初學 (陣列實現連結串列 開放定址法 ) Actor:HT Time:2015年9月29日 Error Reporte: */ #include"stdio.h"

java 解決Hash(雜湊)衝突的四種方法--開放法(線性探測,二次探測,偽隨機探測)、鏈地址法、再雜湊、建立公共溢位區

一)雜湊表簡介 非雜湊表的特點:關鍵字在表中的位置和它之間不存在一個確定的關係,查詢的過程為給定值一次和各個關鍵字進行比較,查詢的效率取決於和給定值進行比較的次數。     雜湊表的特點:關鍵字在表中位置和它之間存在一種確定的關係。 雜湊函式:一般情況下,需要在

王爽 組合語言 實驗7 方式在結構化資料訪問中的應用,用棧實現

assume cs:codesg data segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db

開放法(線性探測),拉鍊法 -Hash演算法

總結: 雜湊別名為:Hash 或者 散列表; 開放定址法是為了解決hash值碰撞後的處理; 散列表(雜湊)是演算法在時間和空間上作出權衡的經典例子。 如果沒有記憶體限制,我們可以直接將鍵作為(可能是一個超大的)陣列的索引,那麼所有查詢操作只需

雜湊表(HashTable)的開放法和鏈地址法的實現

 散列表(Hash table,也叫雜湊表),是根據關鍵碼值(Key value)而直接進行訪問的資料結構。也就是說,它通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。引用(百度) 演算法時間複雜度分析

數據結構之散列(開放法)

測試用例 開放定址法 測試 可能 print 信息 stat gif try 1 // OHash 2 // 關鍵字:int 3 // Hash函數:hash(X) = X mod TableSize 4 // 沖突解決方法:開放定址法。Index(X, i) =

資料表示、方式與指令系統_計算機系統結構第二章_自考本科

概要:計算機系統結構第二章資料表示、定址方式與指令系統知識點小結 一、資料表示(應用) 1、資料表示的定義,資料表示與資料結構的關係     定義:能由計算機硬體識別和引用的資料型別,表現再它有對這種型別的資料進行操作的指令和運算部件 &nbs

雜湊表——開放

一、Hash.h #ifndef __HASH_H__ #define __HASH_H__ #include <stdio.h> #include <stdlib.h> #include <assert.h> typedef int HashDa

演算法導論 第十一章:散列表 筆記(直接表、散列表、通過連結法解決碰撞、雜湊函式、開放法、完全雜湊)

前面討論的各種資料結構中,記錄在各種結構中的相對位置是隨機的,和在記錄的關鍵字之間不存在有確定的關係,因此在查詢記錄是需要進行一系列和關鍵字的比較。而理想的情況是不希望進行任何的比較,一次存取便能得到所查記錄。那就必須在記錄的儲存位置和它的關鍵字之間建立一種確定的關係f,使每個關鍵字和結構中有一

組合語言——彙編的8種方式,以及2個預設段暫存器

1.立即定址方式 MOV AH, 80H(直接給暫存器賦值)2. 暫存器定址方式(源或者目的有一個是暫存器) 2.1) 源運算元是暫存器定址方式 如:ADD VARD, EAX  ADD VARW, AX   MOV VARB, BH等。 其中:VARD、VARW和VARB是雙字,字和位元組

彙編中的方式

儲存器   儲存器(Memory)是現代資訊科技中用於儲存資訊的記憶裝置。其概念很廣,有很多層次,在數字系統中,只要能儲存二進位制資料的都可以是儲存器;在積體電路中,一個沒有實物形式的具有儲存功能的電路也叫儲存器,如RAM、FIFO等;在系統中,具有實物形式的儲存裝置也叫儲存器,如記憶體條、

微控制器的幾種方式

定址就是尋找指令中運算元或運算元所在的地址。所謂定址方式,就是如何找到存放運算元的地址,把運算元提取出來的方法。通常指源運算元的定址方式。 MCS-51系列微控制器定址方式共有七種:暫存器定址、直接定址、立即數定址、暫存器間接定址、變址定址、相對定址、位定址。 1、暫存器定址 暫

(王爽版)彙編實驗7 方式在結構化資料訪問中的應用

題目如下: 彙編程式碼如下: assume cs:codesg ;資料段 data segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db '1984'

組合語言資料方式

資料定址方式 1、 立即數定址 立即數定址:指令需要的運算元緊跟在操作碼之後稱之為指令機器碼的一部分,並隨著處理器的取址操作需要從主存進入指令暫存器。這些運算元用常量形式直接表達,從指令程式碼中立即得到立即數,立即數定址方式只用於指令的原運算元,在傳送指令過程中常用來給暫存器和儲存單

MIPS的暫存器、指令和方式的分類

MIPS的32個暫存器 助記符 編號 作用 zero 0 恆為0 at 1 (assembly temporary)保留給彙編器使用 v0,v1 2-3

真實模式與保護模式的方式

文章目錄 一、真實模式定址 二、保護模式定址 三、參考資料 一、真實模式定址 CPU 在真實模式下,地址匯流排只有 20 位,定址空間為 1 M。 20 位的目標實體地址取決於兩個條件,一是 16 位的段基址,二是

計算機組成原理 方式小結

定址方式小結 定址方式 立即定址 直接把常量寫進指令裡面 運算元作為指令的一部分而直接寫在指令中,這種運算元稱為立即數。這種定址方式也就稱為 立即數定址方式 暫存器定址 指令放暫存器地址 暫存器讀寫資料 指令所要的運算元已儲存在某暫存器中,或把目標運算元 存