導航:首頁 > 解決方法 > 解決沖突的方法為鏈地址法

解決沖突的方法為鏈地址法

發布時間:2022-07-02 14:57:44

㈠ 數據結構

補充問下,這是個創建hashtable的函數,題目各個變數也沒有描述清楚,請提問者審查,以減少回答者不必要的猜測.

㈡ 請列舉四種處理哈希沖突的方法

1、開放地扯法
2、再哈希法
3、鏈地址法
4、建立一個公共溢出區

㈢ 設哈希函數為h(key)=key%19, 解決沖突的方法是鏈地址方法,設計一個從哈希表中刪除關鍵字為key的一個記錄的

int delete(int *s,int key)
{
int flag=0;

if(s==NULL)
return flag;

int *p,*q,loc;
loc=key%19;

if(s[loc]->next==NULL)
return flag;

p=s[loc];
while(p->next->next!=NULL)
{
if(p->next->data==key)
{
q=p->next;
p->next=q->next;
free(q);
flag=1;
}
p=p->next;
}

if(p->next->data==key)
{
q=p->next;
p->next=NULL;
free(q);
flag=1;
}

return flag;
}

㈣ 鏈地址法處理沖突的散列表: 試實現用除留余法構造散列表,鏈地址法處理沖突的散列表類

#include <stdio.h>
#include <malloc.h>

#define NULLKEY 0 // 0為無記錄標志
#define N 10 // 數據元素個數

typedef int KeyType;// 設關鍵字域為整型

typedef struct
{
KeyType key;
int ord;
}ElemType; // 數據元素類型

// 開放定址哈希表的存儲結構
int hashsize[]={11,19,29,37}; // 哈希表容量遞增表,一個合適的素數序列
int m=0; // 哈希表表長,全局變數

typedef struct
{
ElemType *elem; // 數據元素存儲基址,動態分配數組
int count; // 當前數據元素個數
int sizeindex; // hashsize[sizeindex]為當前容量
}HashTable;

#define SUCCESS 1
#define UNSUCCESS 0
#define DUPLICATE -1

// 構造一個空的哈希表
int InitHashTable(HashTable *H)
{
int i;
(*H).count=0; // 當前元素個數為0
(*H).sizeindex=0; // 初始存儲容量為hashsize[0]
m=hashsize[0];
(*H).elem=(ElemType*)malloc(m*sizeof(ElemType));
if(!(*H).elem)
exit(0); // 存儲分配失敗
for(i=0;i<m;i++)
(*H).elem[i].key=NULLKEY; // 未填記錄的標志

return 1;
}

// 銷毀哈希表H
void DestroyHashTable(HashTable *H)
{
free((*H).elem);
(*H).elem=NULL;
(*H).count=0;
(*H).sizeindex=0;
}

// 一個簡單的哈希函數(m為表長,全局變數)
unsigned Hash(KeyType K)
{
return K%m;
}

// 開放定址法處理沖突
void collision(int *p,int d) // 線性探測再散列
{
*p=(*p+d)%m;
}

// 演算法9.17
// 在開放定址哈希表H中查找關鍵碼為K的元素,若查找成功,以p指示待查數據
// 元素在表中位置,並返回SUCCESS;否則,以p指示插入位置,並返回UNSUCCESS
// c用以計沖突次數,其初值置零,供建表插入時參考。
int SearchHash(HashTable H,KeyType K,int *p,int *c)
{
*p=Hash(K); // 求得哈希地址
while(H.elem[*p].key!=NULLKEY&&!(K == H.elem[*p].key))
{
// 該位置中填有記錄.並且關鍵字不相等
(*c)++;
if(*c<m)
collision(p,*c); // 求得下一探查地址p
else
break;
}
if (K == H.elem[*p].key)
return SUCCESS; // 查找成功,p返回待查數據元素位置
else
return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY),p返回的是插入位置
}

int InsertHash(HashTable *,ElemType); // 對函數的聲明

// 重建哈希表
void RecreateHashTable(HashTable *H) // 重建哈希表
{
int i,count=(*H).count;
ElemType *p,*elem=(ElemType*)malloc(count*sizeof(ElemType));
p=elem;
printf("重建哈希表\n");
for(i=0;i<m;i++) // 保存原有的數據到elem中
if(((*H).elem+i)->key!=NULLKEY) // 該單元有數據
*p++=*((*H).elem+i);
(*H).count=0;
(*H).sizeindex++; // 增大存儲容量
m=hashsize[(*H).sizeindex];
p=(ElemType*)realloc((*H).elem,m*sizeof(ElemType));
if(!p)
exit(0); // 存儲分配失敗
(*H).elem=p;
for(i=0;i<m;i++)
(*H).elem[i].key=NULLKEY; // 未填記錄的標志(初始化)
for(p=elem;p<elem+count;p++) // 將原有的數據按照新的表長插入到重建的哈希表中
InsertHash(H,*p);
}

// 演算法9.18
// 查找不成功時插入數據元素e到開放定址哈希表H中,並返回1;
// 若沖突次數過大,則重建哈希表。
int InsertHash(HashTable *H,ElemType e)
{
int c,p;
c=0;
if(SearchHash(*H,e.key,&p,&c)) // 表中已有與e有相同關鍵字的元素
return DUPLICATE;
else if(c<hashsize[(*H).sizeindex]/2) // 沖突次數c未達到上限,(c的閥值可調)
{
// 插入e
(*H).elem[p]=e;
++(*H).count;
return 1;
}
else
RecreateHashTable(H); // 重建哈希表

return 0;
}

// 按哈希地址的順序遍歷哈希表
void TraverseHash(HashTable H,void(*Vi)(int,ElemType))
{
int i;
printf("哈希地址0~%d\n",m-1);
for(i=0;i<m;i++)
if(H.elem[i].key!=NULLKEY) // 有數據
Vi(i,H.elem[i]);
}

// 在開放定址哈希表H中查找關鍵碼為K的元素,若查找成功,以p指示待查數據
// 元素在表中位置,並返回SUCCESS;否則,返回UNSUCCESS
int Find(HashTable H,KeyType K,int *p)
{
int c=0;
*p=Hash(K); // 求得哈希地址
while(H.elem[*p].key!=NULLKEY&&!(K == H.elem[*p].key))
{ // 該位置中填有記錄.並且關鍵字不相等
c++;
if(c<m)
collision(p,c); // 求得下一探查地址p
else
return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY)
}
if (K == H.elem[*p].key)
return SUCCESS; // 查找成功,p返回待查數據元素位置
else
return UNSUCCESS; // 查找不成功(H.elem[p].key==NULLKEY)
}

void print(int p,ElemType r)
{
printf("address=%d (%d,%d)\n",p,r.key,r.ord);
}

int main()
{
ElemType r[N] = {
{17,1},{60,2},{29,3},{38,4},{1,5},
{2,6},{3,7},{4,8},{60,9},{13,10}
};
HashTable h;
int i, j, p;
KeyType k;

InitHashTable(&h);
for(i=0;i<N-1;i++)
{
// 插入前N-1個記錄
j=InsertHash(&h,r[i]);
if(j==DUPLICATE)
printf("表中已有關鍵字為%d的記錄,無法再插入記錄(%d,%d)\n",
r[i].key,r[i].key,r[i].ord);
}
printf("按哈希地址的順序遍歷哈希表:\n");
TraverseHash(h,print);
printf("請輸入待查找記錄的關鍵字: ");
scanf("%d",&k);
j=Find(h,k,&p);
if(j==SUCCESS)
print(p,h.elem[p]);
else
printf("沒找到\n");
j=InsertHash(&h,r[i]); // 插入第N個記錄
if(j==0) // 重建哈希表
j=InsertHash(&h,r[i]); // 重建哈希表後重新插入第N個記錄
printf("按哈希地址的順序遍歷重建後的哈希表:\n");
TraverseHash(h,print);
printf("請輸入待查找記錄的關鍵字: ");
scanf("%d",&k);
j=Find(h,k,&p);
if(j==SUCCESS)
print(p,h.elem[p]);
else
printf("沒找到\n");
DestroyHashTable(&h);

system("pause");
return 0;
}

/*
輸出效果:

表中已有關鍵字為60的記錄,無法再插入記錄(60,9)
按哈希地址的順序遍歷哈希表:
哈希地址0~10
address=1 (1,5)
address=2 (2,6)
address=3 (3,7)
address=4 (4,8)
address=5 (60,2)
address=6 (17,1)
address=7 (29,3)
address=8 (38,4)
請輸入待查找記錄的關鍵字: 17
address=6 (17,1)
重建哈希表
按哈希地址的順序遍歷重建後的哈希表:
哈希地址0~18
address=0 (38,4)
address=1 (1,5)
address=2 (2,6)
address=3 (3,7)
address=4 (4,8)
address=6 (60,2)
address=10 (29,3)
address=13 (13,10)
address=17 (17,1)
請輸入待查找記錄的關鍵字: 13
address=13 (13,10)
請按任意鍵繼續. . .

*/

㈤ 用數據結構鏈地址法解決沖突,編寫插入、刪除和查找演算法

多看看數據結構里的鏈接地址法的相關知識,像基本的插入刪除,查找都有講的。看一點樹,圖的知識。很久沒看書了,也忘記了,呵呵。書上有目錄的都有聯接地址發的敘述的。就是一般的數據結構的書都有吧。主要是在講二叉樹和圖的那些地方有這些存儲方法的數據結構。

如何解決Hash中的沖突問題

1、開放定址法
用開放定址法解決沖突的做法是:當沖突發生時,使用某種探查(亦稱探測)技術在散列表中形成一個探查(測)序列。沿此序列逐個單元地查找,直到找到給定 的關鍵字,或者碰到一個開放的地址(即該地址單元為空)為止(若要插入,在探查到開放的地址,則可將待插入的新結點存人該地址單元)。查找時探查到開放的 地址則表明表中無待查的關鍵字,即查找失敗。注意:
①用開放定址法建立散列表時,建表前須將表中所有單元(更嚴格地說,是指單元中存儲的關鍵字)置空。
②空單元的表示與具體的應用相關。
按照形成探查序列的方法不同,可將開放定址法區分為線性探查法、線性補償探測法、隨機探測等。
(1)線性探查法(Linear Probing)
該方法的基本思想是:
將散列表T[0..m-1]看成是一個循環向量,若初始探查的地址為d(即h(key)=d),則最長的探查序列為:
d,d+l,d+2,…,m-1,0,1,…,d-1
即:探查時從地址d開始,首先探查T[d],然後依次探查T[d+1],…,直到T[m-1],此後又循環到T[0],T[1],…,直到探查到 T[d-1]為止。
探查過程終止於三種情況:
(1)若當前探查的單元為空,則表示查找失敗(若是插入則將key寫入其中);
(2)若當前探查的單元中含有key,則查找成功,但對於插入意味著失敗;
(3)若探查到T[d-1]時仍未發現空單元也未找到key,則無論是查找還是插入均意味著失敗(此時表滿)。
利用開放地址法的一般形式,線性探查法的探查序列為:
hi=(h(key)+i)%m 0≤i≤m-1 //即di=i
用線性探測法處理沖突,思路清晰,演算法簡單,但存在下列缺點:
① 處理溢出需另編程序。一般可另外設立一個溢出表,專門用來存放上述哈希表中放不下的記錄。此溢出表最簡單的結構是順序表,查找方法可用順序查找。
② 按上述演算法建立起來的哈希表,刪除工作非常困難。假如要從哈希表 HT 中刪除一個記錄,按理應將這個記錄所在位置置為空,但我們不能這樣做,而只能標上已被刪除的標記,否則,將會影響以後的查找。
③ 線性探測法很容易產生堆聚現象。所謂堆聚現象,就是存入哈希表的記錄在表中連成一片。按照線性探測法處理沖突,如果生成哈希地址的連續序列愈長 ( 即不同關鍵字值的哈希地址相鄰在一起愈長 ) ,則當新的記錄加入該表時,與這個序列發生沖突的可能性愈大。因此,哈希地址的較長連續序列比較短連續序列生長得快,這就意味著,一旦出現堆聚 ( 伴隨著沖突 ) ,就將引起進一步的堆聚。
(2)線性補償探測法
線性補償探測法的基本思想是:
將線性探測的步長從 1 改為 Q ,即將上述演算法中的 j = (j + 1) % m 改為: j = (j + Q) % m ,而且要求 Q 與 m 是互質的,以便能探測到哈希表中的所有單元。
【例】 PDP-11 小型計算機中的匯編程序所用的符合表,就採用此方法來解決沖突,所用表長 m = 1321 ,選用 Q = 25 。 2、拉鏈法
(1)拉鏈法解決沖突的方法
拉鏈法解決沖突的做法是:將所有關鍵字為同義詞的結點鏈接在同一個單鏈表中。若選定的散列表長度為m,則可將散列表定義為一個由m個頭指針組成的指針數 組T[0..m-1]。凡是散列地址為i的結點,均插入到以T[i]為頭指針的單鏈表中。T中各分量的初值均應為空指針。在拉鏈法中,裝填因子α可以大於 1,但一般均取α≤1。
【例】設有 m = 5 , H(K) = K mod 5 ,關鍵字值序例 5 , 21 , 17 , 9 , 15 , 36 , 41 , 24 ,按外鏈地址法所建立的哈希表如下圖所示:

(2)拉鏈法的優點
與開放定址法相比,拉鏈法有如下幾個優點:
①拉鏈法處理沖突簡單,且無堆積現象,即非同義詞決不會發生沖突,因此平均查找長度較短;
②由於拉鏈法中各鏈表上的結點空間是動態申請的,故它更適合於造表前無法確定表長的情況;
③開放定址法為減少沖突,要求裝填因子α較小,故當結點規模較大時會浪費很多空間。而拉鏈法中可取α≥1,且結點較大時,拉鏈法中增加的指針域可忽略不計,因此節省空間;
④在用拉鏈法構造的散列表中,刪除結點的操作易於實現。只要簡單地刪去鏈表上相應的結點即可。而對開放地址法構造的散列表,刪除結點不能簡單地將被刪結 點的空間置為空,否則將截斷在它之後填人散列表的同義詞結點的查找路徑。這是因為各種開放地址法中,空地址單元(即開放地址)都是查找失敗的條件。因此在 用開放地址法處理沖突的散列表上執行刪除操作,只能在被刪結點上做刪除標記,而不能真正刪除結點。

(3)拉鏈法的缺點
拉鏈法的缺點是:指針需要額外的空間,故當結點規模較小時,開放定址法較為節省空間,而若將節省的指針空間用來擴大散列表的規模,可使裝填因子變小,這又減少了開放定址法中的沖突,從而提高平均查找速度。

㈦ 哈希查找的解決沖突

影響哈希查找效率的一個重要因素是哈希函數本身。當兩個不同的數據元素的哈希值相同時,就會發生沖突。為減少發生沖突的可能性,哈希函數應該將數據盡可能分散地映射到哈希表的每一個表項中。解決沖突的方法有以下兩種:
(1) 開放地址法
如果兩個數據元素的哈希值相同,則在哈希表中為後插入的數據元素另外選擇一個表項。
當程序查找哈希表時,如果沒有在第一個對應的哈希表項中找到符合查找要求的數據元素,程序就會繼續往後查找,直到找到一個符合查找要求的數據元素,或者遇到一個空的表項。
(2) 鏈地址法
將哈希值相同的數據元素存放在一個鏈表中,在查找哈希表的過程中,當查找到這個鏈表時,必須採用線性查找方法。
例3. 6是一個簡單的哈希查找演算法程序,你可以將它和本章結尾的有關代碼一起編譯連接成一個可執行程序。
例3.6一個簡單的哈希查找演算法程序
1: #include<stdlib.h>
2: #include<string.h>
3: #include list.h
4: #include hash.h
5:
6: #define HASH_SIZE 1024
7:
8: static listnode_t *hashTable[HASH_SIZE];
9:
10: void insert(const char * s)
11: {
12: listnode_t *ele = newNode((void * ) s)
13: unsigned int h = hash(s) % HASH_SIZE;
14:
15: ele->next = hashTable[h]
16: hashTable[h] = ele;
17: }
18:
19: void print (void)
20: {
21: int h;
22:
23: for (h = 0; h < HASH_SIZE; h++)
24: {
25: listnode_t * lp = hashTalbe[h];
26:
27: if(lp == NULL)
28: continue;
29: printf([%d] , h);
30: while (lp)
31: {
32: printf( '%s' , lp->u.str)
33: lp = ip->next;
34: }
35: putchar (' ');
36: }
37: }
38:
39: const char *search(const char *s)
40: {
39: unsigned int h = hash(s) % HASH_SIZE;
42: listnode_t * lp = hashTable[h];
43:
44: while (lp)
45: {
46: if (! strcmp (s, lp->u.str))
47: return lp->u.str;
48: lp = lp->next;
49: }
50: return NULL;
51: }
請參見:
3. 4 哪一種查找方法最方便?
3.5 哪一種查找方法最快?
3.8 怎樣查找鏈表中的數據?
_____________________________________________
以下是一個簡單示例:
#include<iostream>
#include<string>
using namespace std;
#define m 5 //人數
#define n 10 //哈希表長度
#define q 7 //隨機數
struct name{
char *py;
int k;
};
name namelist[n];
struct hash{
char *py;
int k;
int s;
};
hash hashlist[n];
void listname()
{
char *f;
int s0,r,i;
namelist[0].py=as;
namelist[1].py=sa;
namelist[2].py=d;
namelist[3].py=f;
namelist[4].py=g;
for(i=0;i<m;i++)
{
s0=0;
f=namelist[i].py;
for(r=0;*(f+r)!='';r++)
s0+=*(f+r);
namelist[i].k=s0;
}
}
void creathash()
{
int i;
for(i=0;i<n;i++)
{
hashlist[i].py=;
hashlist[i].k=0;
hashlist[i].s=0;
}
for(i=0;i<m;i++)
{
int sum=0;
int adr=(namelist[i].k)%q;
int d=adr;
if(hashlist[adr].s==0)
{
hashlist[adr].py=namelist[i].py;
hashlist[adr].k=namelist[i].k;
hashlist[adr].s=1;
}
else
{
while(hashlist[d].k!=0)
{
d=(d+namelist[i].k%5+1)%q;
sum+=1;
}
hashlist[d].py=namelist[i].py;
hashlist[d].k=namelist[i].k;
hashlist[d].s=sum+1;
}
}
}
void find()
{
string nam;
int s0=0,r,sum=1,adr,d;
cout<<請輸入姓名的拼音:<<endl;
cin>>nam;;
for(r=0;r<20;r++)
s0+=nam[r];
adr=s0%q;
d=adr;
if(hashlist[adr].k==s0)
cout<<姓名:<<hashlist[d].py<< <<關鍵字:<<s0<< <<查找長度為: 1<<endl;
else if(hashlist[adr].k==0)
cout<<無此記錄!<<endl;
else
{
int g=0;
while(g==0)
{
d=(d+s0%5+1)%q;
sum+=1;
if(hashlist[d].k==0)
{
cout<<無此記錄!<<endl;
g=1;
}
if(hashlist[d].k==s0)
{
cout<<姓名:<<hashlist[d].py<< <<關鍵字:<<s0<< <<查找長度為: 1<<endl;
g=1;
}
}
}
}
void display()
{
int i;
float av=0;
for(i=0;i<n;i++)
{
cout<<姓名:<<hashlist[i].py<< <<關鍵字:<<hashlist[i].k<<搜索長度:<<hashlist[i].s<<endl;
}
for(i=0;i<7;i++)
{
av+=hashlist[i].s;
}
av/=m;
cout<<平均查找長度:=<<av<<endl;
}
int main()
{
char x;
listname();
creathash();
cout<<d. 顯示哈希表 f. 查找 任意鍵退出 請選擇:<<endl;
while(cin>>x){
if(x=='d'){display(); cout<<endl;}
else if(x=='f'){find();cout<<endl;}
else break;
}
return 0;
}

㈧ 用鏈表和數組實現HASH表,幾種碰撞沖突解決方

1.開放地址法
開放地執法有一個公式:Hi=(H(key)+di) MOD m i=1,2,…,k(k<=m-1)
其中,m為哈希表的表長。di 是產生沖突的時候的增量序列。如果di值可能為1,2,3,…m-1,稱線性探測再散列。
如果di取1,則每次沖突之後,向後移動1個位置.如果di取值可能為1,-1,2,-2,4,-4,9,-9,16,-16,…k*k,-k*k(k<=m/2),稱二次探測再散列。
如果di取值可能為偽隨機數列。稱偽隨機探測再散列。
2.再哈希法
當發生沖突時,使用第二個、第三個、哈希函數計算地址,直到無沖突時。缺點:計算時間增加。
比如上面第一次按照姓首字母進行哈希,如果產生沖突可以按照姓字母首字母第二位進行哈希,再沖突,第三位,直到不沖突為止
3.鏈地址法(拉鏈法)
將所有關鍵字為同義詞的記錄存儲在同一線性鏈表中。
4.建立一個公共溢出區
假設哈希函數的值域為[0,m-1],則設向量HashTable[0..m-1]為基本表,另外設立存儲空間向量OverTable[0..v]用以存儲發生沖突的記錄。

閱讀全文

與解決沖突的方法為鏈地址法相關的資料

熱點內容
裝企簽單技巧方法分享 瀏覽:241
如何快速減肥和燃燒脂肪的方法 瀏覽:274
酸菜餃子怎麼做製作方法 瀏覽:44
柚子皮怎樣做更好看簡單的方法 瀏覽:708
如何養成學生的學習方法 瀏覽:496
農村水管的安裝方法 瀏覽:893
歷史史料的鑒別與解讀方法 瀏覽:654
裁床電腦電剪使用方法 瀏覽:96
如何緩解脖子酸痛按摩方法圖解 瀏覽:86
胸肌鍛煉方法初級健身房 瀏覽:199
平板支撐桿的正確方法 瀏覽:81
怎麼去鍋蓋油污最好方法 瀏覽:327
儲物掛鉤的正確方法 瀏覽:348
老式太陽能上水解決方法 瀏覽:888
巧剝山核桃的方法視頻 瀏覽:942
蘿卜干怎麼腌制保存久方法和步驟 瀏覽:362
褲帶子怎麼打結方法 瀏覽:589
把數看錯的數學題用什麼方法解答 瀏覽:414
青橄欖食用方法 瀏覽:521
空間分析傳統分析方法 瀏覽:972