poj 3320 Jessica's Reading Problem http://acm.pku.edu.cn/JudgeOnline/problem?id=3320
這道題目可以用哈希表法也可以用二分查找法,現在用哈希,二分查找將在后面的博客中推出。
這道題目用到的是數的哈希,對于不需要刪除的字典,哈希表是一種理想的實現方式。
1.哈希表的插入和查找算法
(1)計算函數值h(k)
(2)從槽h(k)開始,使用沖突解決策略定位包含關鍵碼k的紀錄
(3)如果需要插入,再槽內插入即可
兩種操作的復雜度在忽略沖突時是O(1)
2.哈希函數的選取
本題使用最簡單的直接取余法,除數為PRIME,最好是質數,可減小沖突。
3.沖突解決方法
開散列法(這也是大多數情況下使用的)
開散列法也叫拉鏈法,通俗地說就是“既然元素a和b都該放在里面,只好擠一擠了”。即在每個槽里存放所有該放在里面的元素。那么怎么把很多的元素放在槽里呢?只在槽里放一個鏈表表頭就行了,該鏈表中包含所有該放在槽里的元素。但在實際中并不是這樣做的,而是自己維護一個大數組,給鏈表元素分配數組下標,這樣既方便又節省時間和空間。那么鏈表中的元素的排列順序怎樣呢?如果按照查找成功時的效率,顯然可以按照訪問的頻率;而如果按照查找失敗的效率,則可以按照關鍵值排序,即使查找失敗也不需要遍歷整個鏈表。這就是數據結構中的相互矛盾的兩個問題,應根據實際情況協調。
#include<stdio.h>
#define PRIME 99991
struct hashnode
{
int key;
int num;
int next;
}a[1000005];
int b[1000005];
int hashl;
int hash(int num)
{
int i;
i=num%PRIME;
while(a[i].next!=-1)
{
if(num>a[a[i].next].key) //例如hash表中已有8,后面又插入99999時,那么99999>8,需要給99999重新分配 一個下標,即hashl,即前面提到的開散列法解決沖突
break;
else if(num==a[a[i].next].key) //例如hash表中已有8,后面又插入8時,這是只要num++
return a[i].next;
i=a[i].next; //這句用于查找,如果哈希表中已有8和99999,那么你要找8時a[8].next指向的是較大的99999,那么你就必須沿著next走下去,因為這個所謂的鏈表是按減小的順序排序的。最終走到return a[i].next推出while 循環
}
a[hashl].key=num;
a[hashl].next=-1;
a[hashl].num=0;
a[hashl].next=a[i].next;
a[i].next=hashl;
hashl++; //以上6行用于第一次插入元素(即while循環未執行)或while循環break退出的插入
return hashl-1;
}
int main()
{
int n,i,tmp,left,ans;
while(scanf("%d",&n)!=EOF)
{
for(i=0;i<PRIME;i++)
a[i].next=-1;
hashl=PRIME;
left=0;
ans=1;
scanf("%d",&b[0]);
tmp=hash(b[0]);
a[tmp].num++;
for(i=1;i<n;i++)
{
scanf("%d",&b[i]);
tmp=hash(b[i]);
a[tmp].num++;
if(a[tmp].num<=1) //插入的數字以前沒有出現過,肯定包含在ans里
{
ans=i-left+1;
continue;
}
while(1) //對應于if的else,即a[tmp].num>=2,即插入的數字以前出現過。如果是在left位置出現過,則left右移;如果是在“left右邊,i左邊”出現過,則說明目前的i-left+1和ans都可以包括全部的知識點,當然取小的了!
{
tmp=hash(b[left]);
if(a[tmp].num<=1)
break;
a[tmp].num--;
left++;
}
if(ans>i-left+1)
ans=i-left+1;
}
printf("%d\n",ans);
}
return 0;
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/cugbliang/archive/2008/06/01/2497376.aspx
posted on 2009-07-01 13:00
luis 閱讀(684)
評論(0) 編輯 收藏 引用 所屬分類:
轉載 、
并查集*哈希表*類似