色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

哈希表是什么?哈希表數據結構詳細資料分析

算法與數據結構 ? 來源:未知 ? 作者:易水寒 ? 2018-09-24 10:25 ? 次閱讀

我所寫的這些數據結構,都是比較經典的,也是面試中經常會出現的,這篇文章我就不閑扯了,全是干貨,如果你能讀完,希望對你有所幫助~

哈希表也稱為散列表,是根據關鍵字值(key value)而直接進行訪問的數據結構。也就是說,它通過把關鍵字值映射到一個位置來訪問記錄,以加快查找的速度。這個映射函數稱為哈希函數(也稱為散列函數),映射過程稱為哈希化,存放記錄的數組叫做散列表。比如我們可以用下面的方法將關鍵字映射成數組的下標:

arrayIndex=hugeNumber%arraySize

那么問題來了,這種方式對不同的關鍵字,可能得到同一個散列地址,即同一個數組下標,這種現象稱為沖突,那么我們該如何去處理沖突呢?一種方法是開放地址法,即通過系統的方法找到數組的另一個空位,把數據填入,而不再用哈希函數得到的數組下標,因為該位置已經有數據了;另一種方法是創建一個存放鏈表的數組,數組內不直接存儲數據,這樣當發生沖突時,新的數據項直接接到這個數組下標所指的鏈表中,這種方法叫做鏈地址法。下面針對這兩種方法進行討論。

1.開放地址法

1.1 線性探測法

所謂線性探測,即線性地查找空白單元。我舉個例子,如果21是要插入數據的位置,但是它已經被占用了,那么就是用22,然后23,以此類推。數組下標一直遞增,直到找到空白位。下面是基于線性探測法的哈希表實現代碼:

publicclassHashTable {

privateDataItem[] hashArray; //DateItem類是數據項,封裝數據信息

privateint arraySize;

privateint itemNum; //數組中目前存儲了多少項

privateDataItem nonItem; //用于刪除項的

publicHashTable() {

arraySize = 13;

hashArray = newDataItem[arraySize];

nonItem = newDataItem(-1); //deleted item key is -1

}

publicboolean isFull() {

return (itemNum == arraySize);

}

publicboolean isEmpty() {

return (itemNum == 0);

}

publicvoid displayTable() {

System.out.print("Table:");

for(int j = 0; j < arraySize; j++) {

if(hashArray[j] != null) {

System.out.print(hashArray[j].getKey() + " ");

}

else {

System.out.print("** ");

}

}

System.out.println("");

}

publicint hashFunction(int key) {

return key % arraySize; //hash function

}

publicvoid insert(DataItem item) {

if(isFull()) {

//擴展哈希表

System.out.println("哈希表已滿,重新哈希化..");

extendHashTable();

}

int key = item.getKey();

int hashVal = hashFunction(key);

while(hashArray[hashVal] != null && hashArray[hashVal].getKey() != -1) {

++hashVal;

hashVal %= arraySize;

}

hashArray[hashVal] = item;

itemNum++;

}

/*

* 數組有固定的大小,而且不能擴展,所以擴展哈希表只能另外創建一個更大的數組,然后把舊數組中的數據插到新的數組中。但是哈希表是根據數組大小計算給定數據的位置的,所以這些數據項不能再放在新數組中和老數組相同的位置上,因此不能直接拷貝,需要按順序遍歷老數組,并使用insert方法向新數組中插入每個數據項。這叫重新哈希化。這是一個耗時的過程,但如果數組要進行擴展,這個過程是必須的。

*/

publicvoid extendHashTable() { //擴展哈希表

int num = arraySize;

itemNum = 0; //重新記數,因為下面要把原來的數據轉移到新的擴張的數組中

arraySize *= 2; //數組大小翻倍

DataItem[] oldHashArray = hashArray;

hashArray = newDataItem[arraySize];

for(int i = 0; i < num; i++) {

insert(oldHashArray[i]);

}

}

publicDataItemdelete(int key) {

if(isEmpty()) {

System.out.println("Hash table is empty!");

returnnull;

}

int hashVal = hashFunction(key);

while(hashArray[hashVal] != null) {

if(hashArray[hashVal].getKey() == key) {

DataItem temp = hashArray[hashVal];

hashArray[hashVal] = nonItem; //nonItem表示空Item,其key為-1

itemNum--;

return temp;

}

++hashVal;

hashVal %= arraySize;

}

returnnull;

}

publicDataItem find(int key) {

int hashVal = hashFunction(key);

while(hashArray[hashVal] != null) {

if(hashArray[hashVal].getKey() == key) {

return hashArray[hashVal];

}

++hashVal;

hashVal %= arraySize;

}

returnnull;

}

}

classDataItem {

privateint iData;

publicDataItem (int data) {

iData = data;

}

publicint getKey() {

return iData;

}

}

線性探測有個弊端,即數據可能會發生聚集。一旦聚集形成,它會變得越來越大,那些哈希化后落在聚集范圍內的數據項,都要一步步的移動,并且插在聚集的最后,因此使聚集變得更大。聚集越大,它增長的也越快。這就導致了哈希表的某個部分包含大量的聚集,而另一部分很稀疏。

為了解決這個問題,我們可以使用二次探測:二次探測是防止聚集產生的一種方式,思想是探測相隔較遠的單元,而不是和原始位置相鄰的單元。線性探測中,如果哈希函數計算的原始下標是x, 線性探測就是x+1, x+2, x+3, 以此類推;而在二次探測中,探測的過程是x+1, x+4, x+9, x+16,以此類推,到原始位置的距離是步數的平方。二次探測雖然消除了原始的聚集問題,但是產生了另一種更細的聚集問題,叫二次聚集:比如講184,302,420和544依次插入表中,它們的映射都是7,那么302需要以1為步長探測,420需要以4為步長探測, 544需要以9為步長探測。只要有一項其關鍵字映射到7,就需要更長步長的探測,這個現象叫做二次聚集。

二次聚集不是一個嚴重的問題,但是二次探測不會經常使用,因為還有好的解決方法,比如再哈希法。

1.2 再哈希法

為了消除原始聚集和二次聚集,現在需要的一種方法是產生一種依賴關鍵字的探測序列,而不是每個關鍵字都一樣。即:不同的關鍵字即使映射到相同的數組下標,也可以使用不同的探測序列。再哈希法就是把關鍵字用不同的哈希函數再做一遍哈希化,用這個結果作為步長,對于指定的關鍵字,步長在整個探測中是不變的,不同關鍵字使用不同的步長、經驗說明,第二個哈希函數必須具備如下特點:

和第一個哈希函數不同;

不能輸出0(否則沒有步長,每次探索都是原地踏步,算法將進入死循環)。

專家們已經發現下面形式的哈希函數工作的非常好:

stepSize=constant-key%constant

其中 constant 是質數,且小于數組容量。

再哈希法要求表的容量是一個質數,假如表長度為15(0-14),非質數,有一個特定關鍵字映射到0,步長為5,則探測序列是 0,5,10,0,5,10,以此類推一直循環下去。算法只嘗試這三個單元,所以不可能找到某些空白單元,最終算法導致崩潰。如果數組容量為13, 質數,探測序列最終會訪問所有單元。即 0,5,10,2,7,12,4,9,1,6,11,3,一直下去,只要表中有一個空位,就可以探測到它。下面看看再哈希法的代碼:

publicclassHashDouble {

privateDataItem[] hashArray;

privateint arraySize;

privateint itemNum;

privateDataItem nonItem;

publicHashDouble() {

arraySize = 13;

hashArray = newDataItem[arraySize];

nonItem = newDataItem(-1);

}

publicvoid displayTable() {

System.out.print("Table:");

for(int i = 0; i < arraySize; i++) {

if(hashArray[i] != null) {

System.out.print(hashArray[i].getKey() + " ");

}

else {

System.out.print("** ");

}

}

System.out.println("");

}

publicint hashFunction1(int key) { //first hash function

return key % arraySize;

}

publicint hashFunction2(int key) { //second hash function

return5 - key % 5;

}

publicboolean isFull() {

return (itemNum == arraySize);

}

publicboolean isEmpty() {

return (itemNum == 0);

}

publicvoid insert(DataItem item) {

if(isFull()) {

System.out.println("哈希表已滿,重新哈希化..");

extendHashTable();

}

int key = item.getKey();

int hashVal = hashFunction1(key);

int stepSize = hashFunction2(key); //用hashFunction2計算探測步數

while(hashArray[hashVal] != null && hashArray[hashVal].getKey() != -1) {

hashVal += stepSize;

hashVal %= arraySize; //以指定的步數向后探測

}

hashArray[hashVal] = item;

itemNum++;

}

publicvoid extendHashTable() {

int num = arraySize;

itemNum = 0; //重新記數,因為下面要把原來的數據轉移到新的擴張的數組中

arraySize *= 2; //數組大小翻倍

DataItem[] oldHashArray = hashArray;

hashArray = newDataItem[arraySize];

for(int i = 0; i < num; i++) {

insert(oldHashArray[i]);

}

}

publicDataItemdelete(int key) {

if(isEmpty()) {

System.out.println("Hash table is empty!");

returnnull;

}

int hashVal = hashFunction1(key);

int stepSize = hashFunction2(key);

while(hashArray[hashVal] != null) {

if(hashArray[hashVal].getKey() == key) {

DataItem temp = hashArray[hashVal];

hashArray[hashVal] = nonItem;

itemNum--;

return temp;

}

hashVal += stepSize;

hashVal %= arraySize;

}

returnnull;

}

publicDataItem find(int key) {

int hashVal = hashFunction1(key);

int stepSize = hashFunction2(key);

while(hashArray[hashVal] != null) {

if(hashArray[hashVal].getKey() == key) {

return hashArray[hashVal];

}

hashVal += stepSize;

hashVal %= arraySize;

}

returnnull;

}

}

2. 鏈地址法

在開放地址法中,通過再哈希法尋找一個空位解決沖突問題,另一個方法是在哈希表每個單元中設置鏈表(即鏈地址法),某個數據項的關鍵字值還是像通常一樣映射到哈希表的單元,而數據項本身插入到這個單元的鏈表中。其他同樣映射到這個位置的數據項只需要加到鏈表中,不需要在原始的數組中尋找空位。下面看看鏈地址法的代碼:

publicclassHashChain {

privateSortedList[] hashArray; //數組中存放鏈表

privateint arraySize;

publicHashChain(int size) {

arraySize = size;

hashArray = newSortedList[arraySize];

//new出每個空鏈表初始化數組

for(int i = 0; i < arraySize; i++) {

hashArray[i] = newSortedList();

}

}

publicvoid displayTable() {

for(int i = 0; i < arraySize; i++) {

System.out.print(i + ": ");

hashArray[i].displayList();

}

}

publicint hashFunction(int key) {

return key % arraySize;

}

publicvoid insert(LinkNode node) {

int key = node.getKey();

int hashVal = hashFunction(key);

hashArray[hashVal].insert(node); //直接往鏈表中添加即可

}

publicLinkNodedelete(int key) {

int hashVal = hashFunction(key);

LinkNode temp = find(key);

hashArray[hashVal].delete(key);//從鏈表中找到要刪除的數據項,直接刪除

return temp;

}

publicLinkNode find(int key) {

int hashVal = hashFunction(key);

LinkNode node = hashArray[hashVal].find(key);

return node;

}

}

下面是鏈表類的代碼,用的是有序鏈表:

publicclassSortedList {

privateLinkNode first;

publicSortedList() {

first = null;

}

publicboolean isEmpty() {

return (first == null);

}

publicvoid insert(LinkNode node) {

int key = node.getKey();

LinkNode previous = null;

LinkNode current = first;

while(current != null && current.getKey() < key) {

previous = current;

current = current.next;

}

if(previous == null) {

first = node;

}

else {

node.next = current;

previous.next = node;

}

}

publicvoiddelete(int key) {

LinkNode previous = null;

LinkNode current = first;

if(isEmpty()) {

System.out.println("chain is empty!");

return;

}

while(current != null && current.getKey() != key) {

previous = current;

current = current.next;

}

if(previous == null) {

first = first.next;

}

else {

previous.next = current.next;

}

}

publicLinkNode find(int key) {

LinkNode current = first;

while(current != null && current.getKey() <= key) {

if(current.getKey() == key) {

return current;

}

current = current.next;

}

returnnull;

}

publicvoid displayList() {

System.out.print("List(First->Last):");

LinkNode current = first;

while(current != null) {

current.displayLink();

current = current.next;

}

System.out.println("");

}

}

classLinkNode {

privateint iData;

publicLinkNode next;

publicLinkNode(int data) {

iData = data;

}

publicint getKey() {

return iData;

}

publicvoid displayLink() {

System.out.print(iData + " ");

}

}

在沒有沖突的情況下,哈希表中執行插入和刪除操作可以達到O(1)的時間級,這是相當快的,如果發生沖突了,存取時間就依賴后來的長度,查找或刪除時也得挨個判斷,但是最差也就O(N)級別。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 函數
    +關注

    關注

    3

    文章

    4338

    瀏覽量

    62734
  • 數據結構
    +關注

    關注

    3

    文章

    573

    瀏覽量

    40152
  • 哈希表
    +關注

    關注

    0

    文章

    9

    瀏覽量

    4858

原文標題:讀完這篇,希望你能真正理解什么是哈希表

文章出處:【微信號:TheAlgorithm,微信公眾號:算法與數據結構】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    關于哈希沖突解決策略解析

    哈希哈希函數輸入一個鍵,并向返回一個哈希的索引。可能的鍵的集合很大,但是哈希函數值的集合只
    的頭像 發表于 10-10 15:57 ?2939次閱讀
    關于<b class='flag-5'>哈希</b><b class='flag-5'>表</b>沖突解決策略解析

    序列化哈希到文件

    ,s.Number,s.Classes,s.Love})});BinarySerialize.Serialize(strFile, ht); }}}//獲取列表數據,并把列表數據預裝到哈希
    發表于 06-18 18:28

    算法與數據結構——哈希

    周立功教授數年之心血之作《程序設計與數據結構》以及《面向第三章為算法與數據結構,本文為3.5 哈希
    的頭像 發表于 09-25 11:37 ?5570次閱讀
    算法與<b class='flag-5'>數據結構</b>——<b class='flag-5'>哈希</b><b class='flag-5'>表</b>

    基于分段哈希碼的倒排索引樹結構

    哈希技術被視為最有潛力的相似性搜索方法,其可以用于大規模多媒體數據搜索場合。為了解決在大規模圖像情況下,數據檢索效率低下的問題,提出了一種基于分段哈希碼的倒排索引樹
    發表于 11-28 17:40 ?0次下載
    基于分段<b class='flag-5'>哈希</b>碼的倒排索引樹<b class='flag-5'>結構</b>

    java數據結構學習

    數據結構是對計算機內存中的數據的一種安排,數據結構包括 數組, 鏈表, 棧, 二叉樹, 哈希等,算法則對對這些
    發表于 11-29 09:46 ?788次閱讀

    數據結構與算法分析的C語言描述的電子教材詳細資料免費下載

    本文檔的主要內容詳細介紹的是數據結構與算法分析的C語言描述的電子教材詳細資料免費下載
    發表于 08-09 17:36 ?0次下載

    為什么要學習數據結構數據結構的應用詳細資料概述免費下載

    本文檔的主要內容詳細介紹的是為什么要學習數據結構數據結構的應用詳細資料概述免費下載包括了:數據結構在串口通信當中的應用,
    發表于 09-11 17:15 ?13次下載
    為什么要學習<b class='flag-5'>數據結構</b>?<b class='flag-5'>數據結構</b>的應用<b class='flag-5'>詳細資料</b>概述免費下載

    數據結構教程之線性詳細資料說明

    本文檔的主要內容詳細介紹的是數據結構教程之線性詳細資料說明包括了:線性的操作和線性的鏈式表示和實現。
    發表于 04-30 08:00 ?0次下載
    <b class='flag-5'>數據結構</b>教程之線性<b class='flag-5'>表</b>的<b class='flag-5'>詳細資料</b>說明

    哈希是什么?為什么需要使用哈希

    我們在這篇文章將要學習最有用的數據結構之一—哈希哈希的英文叫 Hash Table,也可以稱為散列表或者 Hash
    的頭像 發表于 04-06 13:50 ?1.2w次閱讀
    <b class='flag-5'>哈希</b><b class='flag-5'>表</b>是什么?為什么需要使用<b class='flag-5'>哈希</b><b class='flag-5'>表</b>

    基于C++哈希表解決沖突

    開放尋址是其中一種緩解散列沖突的編程技術,當使用開放尋址作為沖突解決技術時,鍵值對存儲在(數組)中,而不是像單獨鏈表那樣的數據結構中。這意味著我們需要時刻留意哈希的尺寸以及當前
    的頭像 發表于 05-05 23:11 ?1946次閱讀
    基于C++<b class='flag-5'>哈希</b>表解決沖突

    基于Xilinx Virtex-II FPGA的硬件哈希算法的研究分析

    在計算關鍵詞在文檔里出現次數的過程中,需要一種存儲結構來存儲相關信息,這種存儲結構必須易于執行查找、插入及刪除操作。哈希是一種以常數平均時間執行查找、插入和刪除操作的算法。在計算關鍵詞在文檔里的出現次數時應用
    發表于 07-28 17:13 ?1998次閱讀
    基于Xilinx Virtex-II FPGA的硬件<b class='flag-5'>哈希</b>算法的研究<b class='flag-5'>分析</b>

    計算機系統中哈希的優化

    應?能?幅度提升哈希哈希沖突的容忍能?,進?提升查詢的速度,并且能幫助哈希進?極致的存儲空間壓縮。 1 背景
    的頭像 發表于 03-02 14:10 ?2147次閱讀

    一種基于智能放置策略的CucKoo哈希

    由于查詢時間復雜度為O(1), Cuckoo哈希在大數據、云計算等領域得到了廣泛應用。然而,現有 Cuckoo哈希的寫入操作在遇到寫沖突
    發表于 05-13 11:10 ?12次下載

    哈希是什么,它是如何根據鍵來得到值的

    多種哈希算法代碼,用于文件校驗、簡單加密等場合。 哈希也稱作散列表,叫法不同,是一個意思。這種數據結構提供了鍵值對的映射關系,給出鍵就可以快速得到對應的值,比如上面提到的"50號"就
    發表于 06-06 10:10 ?1119次閱讀
    <b class='flag-5'>哈希</b><b class='flag-5'>表</b>是什么,它是如何根據鍵來得到值的

    Linux內核分析 端口哈希

    是用來封裝各種協議的綁定哈希,具體定義如下所示,這個結構體在[Linux內核角度分析服務器Listen細節中介紹過,具體地,struct inet_bind_hashbcket是bi
    的頭像 發表于 07-31 11:03 ?786次閱讀
    Linux內核<b class='flag-5'>分析</b> 端口<b class='flag-5'>哈希</b>桶
    主站蜘蛛池模板: 国产成人免费片在线视频观看| 男男免费看| 成人在线观看国产| 动漫美女被吸奶| 狠狠色丁香婷婷久久综合| 国产VA精品午夜福利视频| 1级午夜影院费免区| 24小时日本高清免费看| 中文字幕国产在线观看| 无码日韩人妻精品久久蜜桃入口| 日本高清无吗| 国产亚洲精品精品精品| 精品久久久噜噜噜久久久app| 久久久久久久网| 青草精品国产福利在线视频| 无套内射CHINESEHD| 孕妇bbwbbwbbwbbw超清| 白丝女仆被啪到深夜漫画| 国产三级影院| 欧美重口绿帽video| 亚洲福利精品电影在线观看| 2020美女视频黄频大全视频| 国产精品俺来也在线观看| 久久热在线视频精品店| 桃隐社区最新最快地址| 91精品国产91热久久p| 国内偷拍夫妻av| 暖暖 免费 高清 日本 在线| 亚洲欧美日韩另类精品一区二区三区| 777米奇色狠狠俺去啦| 国色精品VA在线观看免费视频| 日本大尺码喷液过程视频| 中文字幕 人妻熟女| 海角国精产品一区一区三区糖心| 欧美最新色p图| 综合激情区视频一区视频二区| 国产又湿又黄又硬又刺激视频| 日本湿姝在线观看| av色天堂2018在线观看| 免费精品在线视频| 8090碰成年女人免费碰碰尤物|