摘要:基本版的散列表實(shí)現(xiàn)在散列表中我們通過(guò)散列函數(shù)來(lái)確定鍵值對(duì)的關(guān)系。的實(shí)現(xiàn)具體看的數(shù)據(jù)結(jié)構(gòu)與算法一。散列函數(shù)不超過(guò)數(shù)組的長(zhǎng)度下面兩個(gè)值相同源碼地址的數(shù)據(jù)結(jié)構(gòu)與算法二源碼
1集合 1.1集合的實(shí)現(xiàn)
集合是由一組無(wú)序且唯一(即不能重復(fù))的項(xiàng)組成的。這個(gè)數(shù)據(jù)結(jié)構(gòu)使用了與有限集合相同 的數(shù)學(xué)概念,但應(yīng)用在計(jì)算機(jī)科學(xué)的數(shù)據(jù)結(jié)構(gòu)中。
集合中常用方法列表:
add(value):向集合中添加一個(gè)新的項(xiàng)。
remove(value):從集合中移除一個(gè)值。
has(value):如果在集合中,返回true,否則返回false。
clear():清除集合中的所有項(xiàng)。
size():返回集合所包含元素的數(shù)量。
values():返回一個(gè)包含集合中所有值得數(shù)組。
union(otherSet):并集操作,返回一個(gè)包含兩個(gè)集合中所有元素的新集合。
intersection(otherSet):交集操作,返回一個(gè)包含兩個(gè)集合中共有元素的新集合。
difference(otherSet):差集操作,返回一個(gè)包含左右存在于第一個(gè)集合并且不存在于第二個(gè)集合的元素的新集合。
subset(otherSet):子集操作,驗(yàn)證一個(gè)給定集合是否是另一個(gè)集合的子集,返回true和false。
function Set() { this.items = {}; } Set.prototype = { constructor: Set, has: function(value) { return value in this.items; }, add: function(value) { if (!this.has(value)) { this.items[value] = value; return true; } return false; }, remove: function(value) { if (this.has(value)) { delete this.items[value]; return true; } return false; }, clear: function() { this.items = {}; }, size: function() { return Object.keys(this.items).length; }, values: function() { return Object.keys(this.items); }, union: function(otherSet) { var unionSet = new Set(); var values = this.values(); for (var i = 0; i < values.length; i++) { unionSet.add(values[i]); } values = otherSet.values(); for (var i = 0; i < values.length; i++) { unionSet.add(values[i]); } return unionSet; }, intersection: function(otherSet) { var intersectionSet = new Set(); var values = this.values(); for (var i = 0; i < values.length; i++) { if (otherSet.has(values[i])) { intersectionSet.add(values[i]); } } return intersectionSet; }, difference: function(otherSet) { var differenceSet = new Set(); var values = this.values(); for (var i = 0; i < values.length; i++) { if (!otherSet.has(values[i])) { differenceSet.add(values[i]); } } return differenceSet; }, subset: function(otherSet) { if (this.size() > otherSet.size()) { return false; } else { var values = this.values(); for (var i = 0; i < values.length; i++) { if (!otherSet.has(values[i])) { return false; } } } return true; }, };1.2集合的使用
var set = new Set(); set.add(1); console.log(set.values());//["1"] console.log(set.has(1));//true console.log(set.size());//1 set.add(2); console.log(set.values());//["1","2"] console.log(set.has(2));//true console.log(set.size());//2 set.remove(2); console.log(set.values());//["1"]
交集、并集、子集、差集的使用。
//并集測(cè)試 var setA = new Set(); setA.add(1); setA.add(2); setA.add(3); var setB = new Set(); setB.add(3); setB.add(4); setB.add(5); setB.add(6); var setAB = setA.union(setB); console.log(setAB.values()); // ["1", "2", "3", "4", "5", "6"] //交集測(cè)試 setA = new Set(); setA.add(1); setA.add(2); setA.add(3); setB = new Set(); setB.add(2); setB.add(3); setB.add(4); var intersectionAB = setA.intersection(setB); console.log(intersectionAB.values()); // ["2", "3"] //差集側(cè)事故 setA = new Set(); setA.add(1); setA.add(2); setA.add(3); setB = new Set(); setB.add(2); setB.add(3); setB.add(4); var differenceAB = setA.difference(setB); console.log(differenceAB.values()); //["1"] //子集測(cè)試 setA = new Set(); setA.add(1); setA.add(2); var setB = new Set(); setB.add(1); setB.add(2); setB.add(3); setC = new Set(); setC.add(2); setC.add(3); setC.add(4); console.log(setA.subset(setB)); //true console.log(setA.subset(setC)); //false2字典和散列表
集合、字典和散列表可以存儲(chǔ)不重復(fù)的值。在集合中,我們感興趣的是每個(gè)值本身,并把它 當(dāng)作主要元素。在字典中,我們用[鍵,值]的形式來(lái)存儲(chǔ)數(shù)據(jù)。在散列表中也是一樣(也是以[鍵, 值]對(duì)的形式來(lái)存儲(chǔ)數(shù)據(jù))。
2.1字典集合表示一組互不相同的元素(不重復(fù)的元素)。在字典中,存儲(chǔ)的是[鍵,值] 對(duì),其中鍵名是用來(lái)查詢特定元素的。字典和集合很相似,集合以[值,值]的形式存儲(chǔ)元素,字 典則是以[鍵,值]的形式來(lái)存儲(chǔ)元素。字典也稱(chēng)作映射。下面是字典需要實(shí)現(xiàn)的方法:
set(key,value): 向字典中添加新元素。
remove(key): 通過(guò)使用鍵值來(lái)從字典中語(yǔ)出鍵值對(duì)應(yīng)的數(shù)據(jù)值。
has(key): 如果某個(gè)鍵值存在于這個(gè)字典中,否則返回true,反之則返回false。
get(key): 通過(guò)鍵值查詢特定的數(shù)值并且返回。
clear(): 將這個(gè)字典中的所有元素全部刪除。
size(): 返回字典中包含元素的數(shù)量。
keys(): 將字典所包含的所有鍵名以數(shù)組的形式返回。
values(): 將字典所包含的所有數(shù)值以數(shù)組的形式返回。
getItems(): 返回字典。
2.1.1字典的實(shí)現(xiàn)function Dictionary() { this.items = {}; } Dictionary.prototype = { constructor: Dictionary, has: function(key) { return key in this.items; }, set: function(key, value) { this.items[key] = value; }, remove: function(key) { if (this.has(key)) { delete this.items[key]; return true; } return false; }, get: function(key) { return this.has(key) ? this.items[key] : undefined; }, values: function() { var values = []; for (var key in this.items) { if (this.has(key)) { values.push(key); } } return values; }, clear: function() { this.items = {}; }, size: function() { return Object.keys(this.items).length; }, keys: function() { return Object.keys(this.items); }, getItems: function() { return this.items; } };2.1.2字典的基本使用
var dictionary = new Dictionary(); console.log(dictionary.size()); //0 dictionary.set("first", "huang"); dictionary.set("second", "cheng"); dictionary.set("third", "du"); console.log(dictionary.has("first")); //true console.log(dictionary.get("second")); //cheng console.log(dictionary.values()); // ["first", "second", "third"] dictionary.remove("second"); console.log(dictionary.keys()); //["first", "third"] console.log(dictionary.getItems()); //{ first="huang", third="du"}2.2散列表
HashTable類(lèi),也叫HashMap類(lèi),是Dictionary類(lèi)的一種散列表實(shí)現(xiàn)方式。散列算法的作用是盡可能快地在數(shù)據(jù)結(jié)構(gòu)中找到一個(gè)值。在之前的章節(jié)中,你已經(jīng)知道如果 要在數(shù)據(jù)結(jié)構(gòu)中獲得一個(gè)值(使用get方法),需要遍歷整個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)找到它。如果使用散列 函數(shù),就知道值的具體位置,因此能夠快速檢索到該值。散列函數(shù)的作用是給定一個(gè)鍵值,然后 返回值在表中的地址。
2.2.1基本版的散列表實(shí)現(xiàn)在散列表中我們通過(guò)散列函數(shù)來(lái)確定鍵值對(duì)的關(guān)系。基本方法如下:
put(key,value): 向散列表增加一個(gè)新的選項(xiàng)(也可能是更新散列表)。
remove(key): 根據(jù)鍵值從散列表中移除值。
get(key): 返回根據(jù)鍵值檢索到的特定值。
對(duì)于HashTable類(lèi)來(lái)說(shuō),我們不需要像ArrayList類(lèi)一樣從table數(shù)組中將位置也移除。由 于元素分布于整個(gè)數(shù)組范圍內(nèi),一些位置會(huì)沒(méi)有任何元素占據(jù),并默認(rèn)為undefined值。我們也 不能將位置本身從數(shù)組中移除(這會(huì)改變其他元素的位置),否則,當(dāng)下次需要獲得或移除一個(gè) 元素的時(shí)候,這個(gè)元素會(huì)不在我們用散列函數(shù)求出的位置上。
//lose-los散列函數(shù) function loseloseHashCode(key) { var hash = 0; for (var i = 0; i < key.length; i++) { hash += key.charCodeAt(i); } return hash % 37; } function HashTable() { this.table = []; } HashTable.prototype = { constructor: HashTable, put: function(key, value) { var position = loseloseHashCode(key); console.log(position + "- " + key); this.table[position] = value; }, get: function(key) { return this.table[loseloseHashCode(key)]; }, remove: function(key) { this.table[loseloseHashCode(key)] = undefined; } }; var hash = new HashTable(); hash.put("Gandalf", "gandalf@email.com"); hash.put("John", "johnsnow@email.com"); hash.put("Tyrion", "tyrion@email.com"); console.log(hash.get("Gandalf")); //gandalf@email.com console.log(hash.get("Loiane")); //undefined hash.remove("Gandalf"); console.log(hash.get("Gandalf")); //undefined
有時(shí)候,一些鍵會(huì)有相同的散列值。不同的值在散列表中對(duì)應(yīng)相同位置的時(shí)候,我們稱(chēng)其為沖突。當(dāng)這種情況發(fā)生的時(shí)候就要去解決它。處理沖突有幾種方法:分離鏈接、線性探查和雙散列法,我們會(huì)介紹前兩種方法。對(duì)于分離鏈接和線性探查來(lái)說(shuō),只需要重寫(xiě)三個(gè)方法:put、get和remove。這三個(gè)方法在 每種技術(shù)實(shí)現(xiàn)中都是不同的。
2.2.2分離鏈接版散列表為了實(shí)現(xiàn)一個(gè)使用了分離鏈接的HashTable實(shí)例,我們需要一個(gè)新的輔助類(lèi)來(lái)表示將要加入LinkedList實(shí)例的元素。我們管它叫ValuePair類(lèi)。LinkedList的實(shí)現(xiàn)具體看javascript的數(shù)據(jù)結(jié)構(gòu)與算法(一).html)。
分離鏈接:分離鏈接法包括為散列表的每一個(gè)位置創(chuàng)建一個(gè)鏈表并將元素存儲(chǔ)在里面。它是解決沖突的最簡(jiǎn)單的方法,但是它在HashTable實(shí)例之外還需要額外的存儲(chǔ)空間。
function HashTable() { this.table = []; //lose-los散列函數(shù) function loseloseHashCode(key) { var hash = 0; for (var i = 0; i < key.length; i++) { hash += key.charCodeAt(i); } //console.log(key + " - " + (hash % 37)); return hash % 37; } function ValuePair(key, value) { this.key = key; this.value = value; this.toString = function() { return "[" + this.key + " - " + this.value + "]"; } } if ((typeof this.put !== "function") && (typeof this.put !== "string")) { HashTable.prototype.put = function(key, value) { var position = loseloseHashCode(key); if (this.table[position] === undefined) { this.table[position] = new LinkedList(); } this.table[position].append(new ValuePair(key, value)); }; HashTable.prototype.get = function(key) { var position = loseloseHashCode(key); if (this.table[position] !== undefined) { var current = this.table[position].getHead(); while (current.next) { if (current.element.key === key) { return current.element.value; } current = current.next; } //第一個(gè)元素或者最后一個(gè)元素 if (current.element.key === key) { return current.element.value; } } else { return undefined; } }; HashTable.prototype.remove = function(key) { var position = loseloseHashCode(key); if (this.table[position] !== undefined) { var current = this.table[position].getHead(); while (current.next) { if (current.element.key === key) { this.table[position].remove(current.element); if (this.table[position].isEmpty()) { this.table[position] = undefined; } return true; } current = current.next; } //檢查是否是第一個(gè)或者最后一個(gè) if (current.element.key === key) { this.table[position].remove(current.element); if (this.table[position].isEmpty()) { this.table[position] = undefined; } return true; } } return false; }; } } var hash = new HashTable(); hash.put("Gandalf", "gandalf@email.com"); hash.put("John", "johnsnow@email.com"); //下面兩個(gè)hash值相同 hash.put("Aaron", "huang@gmail.com"); hash.put("Tyrion", "tyrion@email.com"); console.log(hash.get("Gandalf")); //gandalf@email.com console.log(hash.get("Loiane")); //undefined hash.remove("Gandalf"); console.log(hash.get("Gandalf")); //undefined2.2.3線性探查版散列表
另一種解決沖突的方法是線性探查。當(dāng)想向表中某個(gè)位置加入一個(gè)新元素的時(shí)候,如果索引為index的位置已經(jīng)被占據(jù)了,就嘗試index+1的位置。如果index+1的位置也被占據(jù)了,就嘗試 index+2的位置,以此類(lèi)推。
function HashTable() { this.table = []; //lose-los散列函數(shù) function loseloseHashCode(key) { var hash = 0; for (var i = 0; i < key.length; i++) { hash += key.charCodeAt(i); } //console.log(key + " - " + (hash % 37)); return hash % 37; } function ValuePair(key, value) { this.key = key; this.value = value; this.toString = function() { return "[" + this.key + " - " + this.value + "]"; } } if ((typeof this.put !== "function") && (typeof this.put !== "string")) { HashTable.prototype.put = function(key, value) { var position = loseloseHashCode(key); if (this.table[position] === undefined) { this.table[position] = new ValuePair(key, value); } else { var index = position + 1; while (this.table[index] !== undefined) { index++; } this.table[index] = new ValuePair(key, value); } }; HashTable.prototype.get = function(key) { var position = loseloseHashCode(key); if (this.table[position] !== undefined) { if (this.table[position].key === key) { return this.table[position].value; } else { var index = position + 1; //index不超過(guò)數(shù)組的長(zhǎng)度 while (((this.table[index] === undefined) || (this.table[index].key !== key)) && (index < this.table.length)) { index++; } if (this.table[index] && (this.table[index].key === key)) { return this.table[index].value; } else { return undefined; } } } else { return undefined; } }; HashTable.prototype.remove = function(key) { var position = loseloseHashCode(key); if (this.table[position] !== undefined) { if (this.table[position].key === key) { this.table[position] = undefined; return true; } else { var index = position + 1; while ((this.table[index] === undefined) || (this.table[index].key !== key)) { index++; } if (this.table[index].key === key) { this.table[index] = undefined; return true; } } } else { return false; } }; } } var hash = new HashTable(); hash.put("Gandalf", "gandalf@email.com"); hash.put("John", "johnsnow@email.com"); //下面兩個(gè)hash值相同 hash.put("Aaron", "huang@gmail.com"); hash.put("Tyrion", "tyrion@email.com"); console.log(hash.get("Gandalf")); //gandalf@email.com console.log(hash.get("Loiane")); //undefined console.log(hash.remove("Gandalf")); //true console.log(hash.get("Gandalf")); //undefined源碼地址
Javascript的數(shù)據(jù)結(jié)構(gòu)與算法(二)源碼
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/86660.html
摘要:實(shí)現(xiàn)移除給定的元素要移除的元素返回值表示移除成功方法說(shuō)明移除單向鏈表中某個(gè)位置的元素。的前端樂(lè)園原文鏈接寒假前端學(xué)習(xí)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法二鏈表 本系列的第一篇文章: 學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(一),棧與隊(duì)列第二篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(二):鏈表第三篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(三):集合第四篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與...
摘要:技巧使你的更加專(zhuān)業(yè)這是上關(guān)于技巧的一篇譯文,另外你也可以在本項(xiàng)目看到原文。列舉了一些很實(shí)用的技巧,比如給空內(nèi)容的標(biāo)簽添加內(nèi)容,逗號(hào)分隔列表等等。排序算法看源碼,把它背下來(lái)吧排序算法的封裝。主要幫助初學(xué)者更好的掌握排序算法的實(shí)現(xiàn)。 成為專(zhuān)業(yè)程序員路上用到的各種優(yōu)秀資料、神器及框架 成為一名專(zhuān)業(yè)程序員的道路上,需要堅(jiān)持練習(xí)、學(xué)習(xí)與積累,技術(shù)方面既要有一定的廣度,更要有自己的深度。 Java...
摘要:技巧使你的更加專(zhuān)業(yè)這是上關(guān)于技巧的一篇譯文,另外你也可以在本項(xiàng)目看到原文。列舉了一些很實(shí)用的技巧,比如給空內(nèi)容的標(biāo)簽添加內(nèi)容,逗號(hào)分隔列表等等。排序算法看源碼,把它背下來(lái)吧排序算法的封裝。主要幫助初學(xué)者更好的掌握排序算法的實(shí)現(xiàn)。 成為專(zhuān)業(yè)程序員路上用到的各種優(yōu)秀資料、神器及框架 成為一名專(zhuān)業(yè)程序員的道路上,需要堅(jiān)持練習(xí)、學(xué)習(xí)與積累,技術(shù)方面既要有一定的廣度,更要有自己的深度。 Java...
摘要:像剛才的這幅圖,就是二叉搜索樹(shù)。而我們本文要學(xué)習(xí)的內(nèi)容,就是如何寫(xiě)一個(gè)二叉搜索樹(shù)。但在二叉搜索樹(shù)中,我們把節(jié)點(diǎn)成為鍵,這是術(shù)語(yǔ)。前端路漫漫,且行且歌的前端樂(lè)園原文鏈接寒假前端學(xué)習(xí)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法四二叉搜索樹(shù) 本系列的第一篇文章: 學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(一),棧與隊(duì)列第二篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(二):鏈表第三篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)...
摘要:簡(jiǎn)介隊(duì)列遵循的是先進(jìn)先出的原則的一組有序的項(xiàng)。隊(duì)列從尾部添加新元素,并從頂部移除元素,最新添加的元素必須排列在隊(duì)列的末尾。它的想法來(lái)自于生活中排隊(duì)的策略。隊(duì)列不做任何變動(dòng)。 簡(jiǎn)介 隊(duì)列遵循的是FIFO(先進(jìn)先出)的原則的一組有序的項(xiàng)。 隊(duì)列從尾部添加新元素,并從頂部移除元素,最新添加的元素必須排列在隊(duì)列的末尾。 它的想法來(lái)自于生活中排隊(duì)的策略。顧客在付款結(jié)賬的時(shí)候,按照到來(lái)的先后順序排...
摘要:之?dāng)?shù)組操作接下來(lái)就是數(shù)據(jù)結(jié)構(gòu)的第一部分,棧。以字符串顯示棧中所有內(nèi)容方法的實(shí)現(xiàn)說(shuō)明需要往棧中添加新元素,元素位置在隊(duì)列的末尾。的前端樂(lè)園原文鏈接寒假前端學(xué)習(xí)學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法,棧與隊(duì)列 本系列的第一篇文章: 學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(一),棧與隊(duì)列第二篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(二):鏈表第三篇文章:學(xué)習(xí)JavaScript數(shù)據(jù)結(jié)構(gòu)與算法(三):集合第...
閱讀 634·2021-09-22 10:02
閱讀 6326·2021-09-03 10:49
閱讀 565·2021-09-02 09:47
閱讀 2151·2019-08-30 15:53
閱讀 2929·2019-08-30 15:44
閱讀 900·2019-08-30 13:20
閱讀 1812·2019-08-29 16:32
閱讀 889·2019-08-29 12:46