昨天寫了雜湊的開放定址法的部落格,今天我們要說的是拉鍊法,還有乙個名字叫雜湊桶。雜湊桶要做的就是,之前我們用的開放定址法,通過將資料對映到陣列中來實現雜湊。這裡每個陣列的位置只能存放乙個資料,如果衝突的話會繼續往下找找到空的位置然後放進去,但是其實大家都能感覺出來上乙個**很簡單,也很扯,感覺實現起來完全不行,不要說海量資料了,
有點資料感覺就不行了,雖然可以擴容但是也是一件很複雜的事情。這裡我們要實現的是將以前的陣列變成乙個指標陣列,這裡每個資料存放的都是乙個指標,這樣發生衝突的話,就不必要再去找下乙個位置,每發生一次衝突就在當前位置的最後乙個資料後邊掛上另乙個資料。
typedef int keytype;
typedef int valuetype;
typedef struct hashnode
hashnode;
typedef struct hashtable
hashtable;
size_t hashfunc(keytype key, size_t n)
也就是說每個位置放得都是乙個結構體,結構體放著兩個資料,乙個是存放的資料,乙個是next指標。用來尋找下乙個元素。
hashnode
** _tables;
這裡建立的是乙個指標陣列,也就是建立了乙個陣列,陣列中的所有位置的元素都是乙個指標。
hashnode* buyhashnode(keytype key, valuetype value)
分配空間的時候只是多了乙個next指標的初始化。
void hashtableinit(hashtable* ht)
return;
}
初始化中這裡不再是將每個位置置為0而是將每個位置變成null。
int hashtableinsert(hashtable* ht, keytype key, valuetype value)
else
cur = cur->_next;
}next = ht->_tables[index]->_next;
ht->_tables[index] = buyhashnode(key, value);
ht->_tables[index]->_next = next;
}ht->_size++;
return 1;
}
插入函式的時候首先通過對映函式找到你的插入位置,然後判斷這個位置是不是空,是空的話就直接修改這個位置的值,如果不是空的話,你就需要找當前位置的下邊所有的元素是不是有你當前的元素,這時候你就需要遍歷了,如果沒有的話才能插入這個元素,如果有的話,那就不能加入當前元素。如果找到最後沒有的話,
我們就用頭插法插入當前的元素。
hashnode* hashtablefind(hashtable* ht, keytype key)
return null;
}
查詢函式,這些都是對鍊錶的基本操作也不需要過多的介紹。
int hashtableremove(hashtable* ht, keytype key)
else//不是第乙個
free(cur);
ht->_size--;
return 0;
}prev = cur;
cur = cur->_next;
}return -1;
}
刪除元素的時候也要判斷是不是第乙個位置,兩種情況需要不同的解決辦法。
size_t getnextprimenum(size_t cur)
;for (i = 0; i < 28; i++)
}
這個函式應該在上次就寫了,但是這次才寫出來,這是乙個素數表的函式,也就是說每次擴充套件陣列的時候,陣列的大小都是已經確定了,就是陣列中的這些元素,這裡為什麼採用素數大家也一定很容易理解。素數除了它本身和1不能被任何乙個數整除,又因為我們的對映方式就是採用了餘數法,所以這裡素數的話就能在一定程度上緩解雜湊衝突。
int hashtableremove(hashtable* ht, keytype key)
else//不是第乙個
free(cur);
ht->_size--;
return 0;
}prev = cur;
cur = cur->_next;
}return -1;
}
刪除也是對鍊錶的基本操作。
void hashtabledestory(hashtable* ht)
}free(ht->_tables);
ht->_n = 0;
ht->_size = 0;
}hashtable *check(hashtable* ht)
}hashtabledestory(ht);
return &newht;
}else
}
擴容函式這裡思路和上次是一樣的,還是不斷的讀取數,然後插入進去,不過這裡還有乙個相對簡單的辦法,不過我沒有寫出來,這裡不同於陣列,這裡是鍊錶,我是可以重複利用所開闢的空間的,也就是說假如我們現在插入了乙個元素1,給她分配好了空間,然後插入到了第乙個指標陣列中,當擴容的時候就可以直接把這裡鍊錶直接連線過去,但是可以直接將陣列下邊的一串直接對應到新的陣列對應的位置嗎?不行,為什麼因為你擴充陣列的時候,每個資料要對應的位置也發生了變化所以你需要讀取資料後算出他對應的新位置,然後直接將這個結構體摘下來放到新的指標陣列裡邊不需要再給他們重新開闢空間了,這是乙個方便的相對辦法。這裡我沒有寫出來。
雜湊的初衷是想將你的查詢時間不短你的縮短,讓你時間複雜度控制到o(1),但是這是乙個十分理想的情況才能達到的狀態。雜湊開放定址法的時候我們會有負載因子,一般是0.7也就是說,當你的元素佔了陣列總元素百分之七十的時候,就需要進行擴充你的陣列長度,但是這裡可以適當的擴大你的負載因子可以擴充到1。
雜湊表(閉雜湊 拉鍊法 雜湊桶)
雜湊表,也稱雜湊表,是一種通過key值來直接訪問在記憶體中的儲存的資料結構。它通過乙個關鍵值的函式 被稱為雜湊函式 將所需的資料對映到表中的位置來訪問資料。關於雜湊表,主要為以下幾個方面 一 雜湊表的幾種方法 1 直接定址法 取關鍵字key的某個線性函式為雜湊位址,如hash key key 或 h...
雜湊桶的各操作總結 拉鍊法
0.定義結構 雜湊表中結點的型別 拉鍊法 typedef struct hashnode hashnode 雜湊表的型別 typedef struct hashtablebucket htb 1.介面宣告 初始化 void htbinit htb htb,size t len 銷毀雜湊表 void ...
雜湊表(拉鍊法)
開雜湊法又叫鏈位址法 開鏈法 開雜湊法 首先對關鍵碼集合用雜湊函式計算雜湊位址,具有相同位址的關鍵碼歸於同一子集合,每乙個子集合稱為乙個桶,各個 桶中的元素通過乙個單鏈表鏈結起來,各鍊錶的頭結點儲存在雜湊表中。設元素的關鍵碼為37,25,14,36,49,68,57,11,雜湊表為ht 12 表的大...