資料結構雜湊表(c語言)

古月流砥發表於2020-12-27
  1. 雜湊表概念
    決定一個雜湊表的主要是雜湊函式處理衝突的方法。而按照設定的雜湊函式和處理衝突的方法將一組關鍵字key 對映到有限的地址集合中,這就是雜湊表。可以根據處理衝突的方法不同,給雜湊表不同的命名,如:鏈式雜湊表,開放址雜湊表。

  2. 雜湊函式構造方法
    直接定義法:程式碼塊如下:

int hash1(int key){
return a*key + b; //a 縮放, b 平移
}

除留取餘法:(我接觸最多的)
區間長度為 m 的雜湊表,取 不大於 m 的數 x 為模, H(key) = key % p。(理論上,p 取最接近 m 的素數最好了)

int hash2(int key){
return key % p;
}

數字分析法:瞭解不多,貌似沒用到過。
摺疊法:
移位摺疊

int  hash3(int key){
itn i , j= 1, qu , sum = 0;
for (i = 0; i < w; i++) 
j * = 10;//按照w 位分割
while (key != 0){
qu = key % j;
sum += qu;
key /= j;
}
return sum;
}

平方取中法 :接觸的很少(沒有)

  1. 處理衝突
    當關鍵字key的數量大於雜湊地址的元素個數時,就一定會產生衝突(幾個不同的key 在同一個雜湊地址)可以理解為一個關於x , y 的函式, x (key)不同時 , y (地址)是相同的 ,x1 != x2, 但是H(x1) = H(x2),這就是衝突。
    處理衝突的方法:
    鏈地址法:關鍵字為同一個地址的連結在同一個單連結串列中。
    開放地址法:
    Hi=(H(key)+di)% m ( i=1,2,…,n)
    1,線性探測:如果這個地址已經有元素了,就到下一個地址,直到找到空地址或者瀏覽完全表。
    di = 1,2,3……
    2,二次探測:左右跳躍的看
    di = 12,-12,22-22……
  2. 雜湊表的實現
    1,開放地址雜湊表(在論壇看了大佬的程式碼,然後自己思考寫了一份,用的是線性探測)
#include <stdio.h>
#include <stdlib.h>
//巨集定義相關常量
#define Max  10
#define Size  10

typedef struct Sqlist{
int *data;
int length;//長度
}Sqlist;//順序表

typedef struct HashSqlist{
int *data;
int length;
}HashSqlist;//雜湊表

int hash (int key){
return key%10;
}  //雜湊函式

void InitSqlist(Sqlist &l){ //這裡l 還沒定義,所以要加 &
printf("Please int the length of the hashTable\n");
scanf("%d",&l.length);
l.data = (int *)malloc (Max * sizeof(int));
printf("Please int %d numbers\n",l.length);
for (int i = 0; i < l.length ; i ++)
scanf("%d",&l.data[i]);
}//建立一個順序表,通過順序表給雜湊表賦值

void InitHashSqlist(Sqlist l,HashSqlist &hl){
hl.data = (int *)malloc (Max * sizeof (int ));
hl.length = Size;
int i,j,key;
for (i = 0; i < hl.length; i ++)
hl.data[i] = 0;
for (i = 0; i < l.length ; i ++){
key = hash(l.data[i]);
if (hl.data [key]  != NULL){
for (j = 1;  hl.data[key] != NULL; j ++)
key = hash(l.data[i] + j);
}
hl.data[key] = l.data[i] ;
printf("%d ----%d \n",key,hl.data[key]);//順便輸出,方便檢驗
}
}

int main (){
Sqlist l;
HashSqlist hl;
InitSqlist(l);
InitHashSqlist(l,hl);
return 0;
}
//目前只是初始化並且輸出一個雜湊表,有時間(學會後)再補上:查詢、刪除、替換等功能。

	

鏈式雜湊表

#include  <stdio.h>
#include <stdlib.h>
#define Max 10
#define Size 10
typedef struct Sqlist {
int *data;
int length;
}Sqlist;

typedef struct HashSqlist{
int *data;
int length;
}HashSqlist;

typedef struct Lnode{
int data;
struct Lnode * next;
}Lnode,*HLinklist; //單連結串列

typedef struct Hnode {
Lnode *first;
}Hnode,Hlist[Max];//定義一個指向連結串列第一個地址的雜湊連結串列

typedef struct HashTable{
	 Hlist arr;//雜湊錶鏈地址 
	int listNumber;//雜湊地址個數 
}HashTable;

int hash(int key ){
return key % 10;
}

void InitSqlist(Sqlist &l){
printf("Please int the length of the hashTable\n");
scanf("%d",&l.length);
l.data = (int *)malloc (Max * sizeof(int ));
printf("Please int %d numbers\n",l.length);
for (int i = 0; i < l.length ; i ++)
scanf("%d",&l.data[i] );
}

void InitHashTable(Sqlist l,HashTable &ht){
Lnode *p,*q;
ht.listNumber = l.length;
int i , j , key;
for (i  = 0; i < ht.listNumber; i ++)
ht.arr[i].first = NULL;
for(i = 0;i < l.length;i++){
		p=(Lnode*)malloc(sizeof(Lnode));
		p->data=l.data[i];
		p->next=NULL;
		key=hash(l.data[i]);
		if (key > ht.listNumber)
		ht.listNumber = key;
		q=ht.arr[key].first;
		if(q){
			while(q->next){
				q=q->next ;
			}
			q->next=p;
		}
		else
			ht.arr[key].first=p;		
	}
	return;	
} 

void Output(HashTable ht){
	int i;
	HLinklist p,q;	
	for(i=0;i<=ht.listNumber;i++){
		p=ht.arr[i].first;
		printf("%d----",i);
		while(p){
			printf("%d->",p->data);
			p=p->next;	
		}
		printf("\n");
	}
	return ;
}

int main(){
 Sqlist l;
 HashTable ht;
 InitSqlist(l);
 InitHashTable(l,ht);// 鏈地址法解決衝突 
 Output(ht);
 return 0;	
}
//同樣的,這個也只實現了初始化並且輸出。學會後再更新。

相關文章