摘要:對(duì)散列表的簡(jiǎn)單學(xué)習(xí)類(lèi)也叫類(lèi),是類(lèi)的一種散列表實(shí)現(xiàn)方式。鍵值散列函數(shù)散列值形成散列表地址數(shù)據(jù)鍵值對(duì)相關(guān)操作方法創(chuàng)建一個(gè)散列表實(shí)現(xiàn)一個(gè)散列函數(shù),即將碼值相加的方法。
對(duì)JS散列表的簡(jiǎn)單學(xué)習(xí)
HashTable類(lèi)也叫HashMap類(lèi),是Dictionary類(lèi)的一種散列表實(shí)現(xiàn)方式。
散列算法的作用是盡可能快的在數(shù)據(jù)結(jié)構(gòu)中找到一個(gè)值。
在之前的學(xué)習(xí)中,如果你想要獲得數(shù)據(jù)結(jié)構(gòu)中的一個(gè)值,需要遍歷整個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)找到它。如果使用散列函數(shù),就能知道具體位置,也就能夠快速找到該值。
使用最常見(jiàn)的散列函數(shù)--‘lose lose’散列函數(shù),簡(jiǎn)單的將每個(gè)鍵值中的每個(gè)字母的ASCII碼值相加,將得到的散列值作為地址。
(鍵值)John (散列函數(shù))74+111+104+110 (散列值)399 形成散列表
地址 | 數(shù)據(jù)鍵值對(duì) |
---|---|
[399] | john/[email protected] |
... | |
[685] | gandalf/@email.com |
創(chuàng)建一個(gè)散列表
function HashTable() { var table = []; }
實(shí)現(xiàn)一個(gè)散列函數(shù),即將ASCII碼值相加的方法。
var loseloseHashTable = function(key) { var hash = 0; for(var i = 0; i < key.length; i++) { hash += key.charCodeAt(i); } return hash % 37; //這里只是為了得到比較小的數(shù)值,隨便除了一個(gè)數(shù) }
實(shí)現(xiàn)put(key, value)方法,向散列表中添加一個(gè)新的項(xiàng)。
this.put = function (key, value) { var position = loseloseHashTable(key); //得到散列值,即位置 table[position] = value; };
實(shí)現(xiàn)get(key)方法,返回根據(jù)鍵值檢索到的特定的值。
this.get = function(key) { var position = loseloseHashTable(key); return table[position]; };
實(shí)現(xiàn)remove()方法,從散列中移除鍵值對(duì)應(yīng)的數(shù)據(jù)值。
this.remove = function(key) { table[loseloseHashTable(key)] = undefined; //沒(méi)有數(shù)據(jù)占據(jù)的位置默認(rèn)值為undefined };
具體使用方法這里就不贅述了,就是方法的調(diào)用。
沖突怎么辦?假如有多個(gè)鍵值得到的散列值相等,那么后面的元素會(huì)覆蓋前面前面相同散列值的元素,
怎么解決呢?
分離鏈接
分離鏈接法為散列表的每一個(gè)位置創(chuàng)建一個(gè)鏈表并將元素存儲(chǔ)在里面。
地址 | 鏈表存儲(chǔ)數(shù)據(jù) |
---|---|
[5] | [no1/no1.com]指針-> [no2/no2.com]指針-> [X]null |
在地址5上,鏈表實(shí)例上有兩個(gè)元素no1.com和no2.com。
需要添加一個(gè)valuePair類(lèi),來(lái)表示將要加入鏈表的實(shí)例的元素。
var valuePair = function(key, value) { this.key = key; this.value = value; this.toString = function() { return `[${this.key} - ${this.value}]`; } }
重寫(xiě)一個(gè)put()方法
this.put = function(key, value) { var position = loseloseHashTable(key); if(table[position] == undefined) { table[position] = new LinkedList(); //如果這個(gè)位置是第一次被加入元素,那么就初始化一個(gè)LinkedList實(shí)例 } table[position].append(new valuePair(key, value)); //鏈表實(shí)現(xiàn)的append方法添加一個(gè)valuePair實(shí)例。 };
重寫(xiě)一個(gè)get(key)方法
this.get = function(key) { var position = loseloseHashTable(key); if(table[position] !== undefined) { //位置上有元素存在 //遍歷鏈表來(lái)尋找鍵/值 var current = table[position].getHead(); while (current.next) { //這里遍歷不到鏈表最后一個(gè)位置 if(current.element.key === key) { return current.element.value; //element屬性是valuePair的實(shí)例,包含key和value屬性 } current = current.next; } //檢查元素在鏈表第一個(gè)或者最后一個(gè)的情況 if(current.element.key === key) { return current.element.value; } } return undefined; //位置上沒(méi)有值 };
重寫(xiě)remove(key)方法
this.remove = function(key) { var position = loseloseHashTable(key); if(table[position] !== undefined) { var current = table[position].getHead(); while (current.next) { if(current.element.key === key) { table[position].remove(current.element); //鏈表實(shí)現(xiàn)的remove方法 if(table[position].isEmpty()) { //刪除元素之后判斷鏈表是否變空 table[position] = undefined; } return true; } current = current.next; } //檢查是否是第一個(gè)或者最后一個(gè)元素 if(current.element.key === key) { table[position].remove(current.element); if(table[position].isEmpty()) { table[position] = undefined; } return true; } } return false; }
線(xiàn)性探查
如果索引為index的位置已經(jīng)被占據(jù)了,就嘗試index+1的位置,以此類(lèi)推。
5的位置被占據(jù),就尋找6的位置,6的位置被占據(jù),就找7,7沒(méi)被占據(jù)就賦值(本應(yīng)該在位置5上,但是線(xiàn)性探查變成了位置7)
實(shí)現(xiàn)put(key, value)方法
this.put = function(key, value) { var position = loseloseHashTable(key); if(table[position] === undefined) { //這個(gè)位置沒(méi)有被占據(jù) table[position] = new valuePair(key, value); } else { var index = ++position; //尋找下一個(gè)位置 while(table[index] !== undefined) { //被占據(jù)繼續(xù)尋找下一個(gè)位置 index ++; } table[index] = new valuePair(key, value); } };
實(shí)現(xiàn)get()方法
this.get = function(key) { var position = loseloseHashTable(key); if(table[position] !== undefined) { if(table[position].key === key) { //舉例位置5 return table[position].value; //記號(hào)1 } else { var index = ++position; while(table[index] !== undefined && (table[index] && table[index].key !== key)) { //該位置有元素但是不是要尋找的元素 index ++; //索引增加 } if(table[index] && table[index].key === key) { //確認(rèn)正確性 return table[index].value; //找到7 //記號(hào)2 } } } return undefined; };
實(shí)現(xiàn)remove()方法
只需要改變get方法的記號(hào)1和記號(hào)2的位置代碼即可
改為table[index] = undefined;
var djb2HashCode = function(key) { var hash = 5381; //初始化一個(gè)hash變量并賦值為一個(gè)質(zhì)數(shù)5381 for(var i = 0; i < key.length; i++) { //遍歷 hash = hash * 33 + key.charCodeAt(i); } return hash % 1013; }
相比來(lái)說(shuō),沖突會(huì)變少很多~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88223.html
摘要:我對(duì)字典的簡(jiǎn)單學(xué)習(xí)字典的概念集合字典和散列表都可以來(lái)存儲(chǔ)不重復(fù)的值。字典也被稱(chēng)為映射。中有集合類(lèi)的實(shí)現(xiàn),也有字典類(lèi)的實(shí)現(xiàn)。相關(guān)操作方法實(shí)現(xiàn)方法,判斷某個(gè)鍵值是否在這個(gè)字典中,有則返回。實(shí)現(xiàn)方法,將字典所有的值以數(shù)組的形式返回。 我對(duì)JS字典的簡(jiǎn)單學(xué)習(xí) 字典的概念 集合、字典和散列表都可以來(lái)存儲(chǔ)不重復(fù)的值。在集合中我們使用[值,值]來(lái)保存,在字典和散列表中使用[鍵,值]來(lái)存儲(chǔ)數(shù)據(jù)。 字典...
摘要:小結(jié)實(shí)現(xiàn)了字典和哈希表感覺(jué)沒(méi)有想象中那么困難,當(dāng)然這還是開(kāi)始。 本系列所有文章:第一篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之棧與隊(duì)列第二篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之鏈表第三篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之集合第四篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之字典和散列表第五篇文章:學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法之二叉搜索樹(shù) 字典 不是新華字典哦,這里的字典也稱(chēng)作_映射_,是一種數(shù)據(jù)結(jié)構(gòu),跟set集合很相似的一種數(shù)據(jù)結(jié)構(gòu),都可以用來(lái)...
摘要:我經(jīng)常在業(yè)務(wù)代碼中把數(shù)據(jù)處理成這種字典的數(shù)據(jù)結(jié)構(gòu)獲取的方法哈希表在學(xué)習(xí)了類(lèi)之后,我們會(huì)學(xué)習(xí)散列表,也就是哈希表。 《Javascript數(shù)據(jù)結(jié)構(gòu)和算法》筆記-「字典和散列表」 集合、字典、散列表存儲(chǔ)的都是「不重復(fù)」的數(shù)據(jù)結(jié)構(gòu) 集合:我們更關(guān)注每一個(gè)元素的值,并把其作為主要元素 字典:我們用[鍵,值]的形式來(lái)存儲(chǔ)數(shù)據(jù) 散列表: 跟字典類(lèi)似,也會(huì)是用[鍵,值]的形式來(lái)存儲(chǔ)數(shù)據(jù) 但是「字...
摘要:我對(duì)鏈表的學(xué)習(xí)什么是鏈表要存儲(chǔ)多個(gè)元素,數(shù)組可能是最常用的數(shù)據(jù)結(jié)構(gòu)。鏈表的學(xué)習(xí)創(chuàng)建一個(gè)鏈表各種方法表示要加入列表的項(xiàng),它包含一個(gè)屬性以及一個(gè)屬性,表示要添加到列表的值,表示指向列表下一個(gè)節(jié)點(diǎn)項(xiàng)的指針。 我對(duì)JS鏈表的學(xué)習(xí) 什么是鏈表 要存儲(chǔ)多個(gè)元素,數(shù)組可能是最常用的數(shù)據(jù)結(jié)構(gòu)。這種數(shù)據(jù)結(jié)構(gòu)非常方便,但是有一個(gè)缺點(diǎn):從數(shù)組的起點(diǎn)或者中間插入或移除項(xiàng)的成本非常高,因?yàn)樾枰苿?dòng)元素(比如你插...
摘要:并且,我們的底層都是紅黑樹(shù)來(lái)實(shí)現(xiàn)的。紅黑樹(shù)是一種平衡二叉樹(shù)因此它沒(méi)有節(jié)點(diǎn)。 前言 聲明,本文用得是jdk1.8 前面已經(jīng)講了Collection的總覽和剖析List集合: Collection總覽 List集合就這么簡(jiǎn)單【源碼剖析】 原本我是打算繼續(xù)將Collection下的Set集合的,結(jié)果看了源碼發(fā)現(xiàn):Set集合實(shí)際上就是HashMap來(lái)構(gòu)建的! showImg(https:/...
閱讀 1437·2023-04-25 18:34
閱讀 3547·2021-11-19 09:40
閱讀 2853·2021-11-17 09:33
閱讀 3001·2021-11-12 10:36
閱讀 2866·2021-09-26 09:55
閱讀 2683·2021-08-05 10:03
閱讀 2548·2019-08-30 15:54
閱讀 2895·2019-08-30 15:54