集合是由一組無序且惟一的項組成。這個數據結構使用了與有限集合相同的數學概念。前端
function Set(){ var items = {}; }
add(value) -- 向集合添加一個新的項
remove(value) -- 從集合移除一個值
has(value) -- 若是值在集合中,返回true,不然返回false
clear() -- 移除集合中的全部項
size() -- 返回集合所包含元素的數量
values() -- 返回一個包含集合中全部值的數值vue
function Set(){ var items = {}; this.has = function(value){ return items.hasOwnProperty(value); }; this.add = function(value) { if(!this.has(value)){ items[value] = value; return true; } return false; }; this.remove = function(value) { if(this.has(value)){ delete items[value]; return true; } return false; }; this.clear = function() { items = {}; }; this.size = function () { return Object.keys(items).length; }; this.values = function(){ return Object.keys(items); }; }
並集--對於給定的兩個集合,返回一個包含兩個集合中全部元素的新集合。es6
this.union = function(otherSet) { var unionSet = new Set(); var values = this.values(); for(var i=0;i<values.length;i++){ unionSet.add(value[i]); } values = otherSet.values(); for(var i=0;i<values.length;i++) { unionSet.add(values[i]); } return unionSet; }
交集 -- 集合A和B的交集是元素存在於A中,其存在於B中。面試
this.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; }
差集 -- 集合A和B的差集,是元素存在於A中,且元素不存在於B中。算法
this.difference = function(otherSet){ var differenceSet = new Set(); var values = this.values(); for(var i=0; i<values.length;i++){ if(!otherSet.has(value[i)){ differenceSet.add(values[i]); } } return differenceSet; }
ES6的標準中實現了Set的數據結構,它能夠這樣被使用。segmentfault
const s = new Set(); [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); for (let i of s) { console.log(i); } // 2 3 5 4
Set 結構的實例有如下屬性。數組
Set.prototype.constructor:構造函數,默認就是Set函數。數據結構
Set.prototype.size:返回Set實例的成員總數函數
Set 實例的方法分爲兩大類:操做方法(用於操做數據)和遍歷方法(用於遍歷成員)。下面先介紹四個操做方法。this
add(value):添加某個值,返回Set結構自己。
delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
has(value):返回一個布爾值,表示該值是否爲Set的成員。
clear():清除全部成員,沒有返回值。
*去除數值重複元素的方法
// 去除數組的重複成員 [...new Set(array)]
*Array.from方法能夠將 Set 結構轉爲數組。
const items = new Set([1, 2, 3, 4, 5]); const array = Array.from(items);
Set 結構的實例有四個遍歷方法,能夠用於遍歷成員。
keys():返回鍵名的遍歷器
values():返回鍵值的遍歷器
entries():返回鍵值對的遍歷器
forEach():使用回調函數遍歷每一個成員
Set的遍歷順序就是插入順序。這個特性有時很是有用,好比使用Set保存一個回調函數列表,調用時就能保證按照添加順序調用。keys
方法、values
方法、entries
方法返回的都是遍歷器對象。因爲 Set 結構沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個值),因此keys方法和values方法的行爲徹底一致。
let set = new Set(['red', 'green', 'blue']); for (let item of set.keys()) { console.log(item); } // red // green // blue for (let item of set.values()) { console.log(item); } // red // green // blue for (let item of set.entries()) { console.log(item); } // ["red", "red"] // ["green", "green"] // ["blue", "blue"]
Set結構的實例的forEach方法,用於對每一個成員執行某種操做,沒有返回值。
let set = new Set([1, 2, 3]); set.forEach((value, key) => console.log(value * 2) ) // 2 // 4 // 6
實現並集(Union)、交集(Intersect)和差集(Difference)
let a = new Set([1, 2, 3]); let b = new Set([4, 3, 2]); // 並集 let union = new Set([...a, ...b]); // Set {1, 2, 3, 4} // 交集 let intersect = new Set([...a].filter(x => b.has(x))); // set {2, 3} // 差集 let difference = new Set([...a].filter(x => !b.has(x))); // Set {1}
WeakSet 結構與 Set 相似,也是不重複的值的集合。可是,它與 Set 有兩個區別。
首先,WeakSet 的成員只能是對象,而不能是其餘類型的值。
const ws = new WeakSet(); ws.add(1) // TypeError: Invalid value used in weak set ws.add(Symbol()) // TypeError: invalid value used in weak set
上面代碼試圖向 WeakSet 添加一個數值和Symbol值,結果報錯,由於 WeakSet 只能放置對象。
其次,WeakSet 中的對象都是弱引用,即垃圾回收機制不考慮 WeakSet 對該對象的引用,也就是說,若是其餘對象都再也不引用該對象,那麼垃圾回收機制會自動回收該對象所佔用的內存,不考慮該對象還存在於 WeakSet 之中。
這是由於垃圾回收機制依賴引用計數,若是一個值的引用次數不爲0,垃圾回收機制就不會釋放這塊內存。結束使用該值以後,有時會忘記取消引用,致使內存沒法釋放,進而可能會引起內存泄漏。WeakSet 裏面的引用,都不計入垃圾回收機制,因此就不存在這個問題。所以,WeakSet 適合臨時存放一組對象,以及存放跟對象綁定的信息。只要這些對象在外部消失,它在 WeakSet 裏面的引用就會自動消失。
因爲上面這個特色,WeakSet 的成員是不適合引用的,由於它會隨時消失。另外,因爲 WeakSet 內部有多少個成員,取決於垃圾回收機制有沒有運行,運行先後極可能成員個數是不同的,而垃圾回收機制什麼時候運行是不可預測的,所以 ES6 規定 WeakSet 不可遍歷。
WeakSet 結構有如下三個方法。
WeakSet.prototype.add(value):向 WeakSet 實例添加一個新成員。
WeakSet.prototype.delete(value):清除 WeakSet 實例的指定成員。
WeakSet.prototype.has(value):返回一個布爾值,表示某個值是否在WeakSet 實例之中。
const ws = new WeakSet(); const obj = {}; const foo = {}; ws.add(window); ws.add(obj); ws.has(window); // true ws.has(foo); // false ws.delete(window); ws.has(window); // false
WeakSet沒有size屬性,沒有辦法遍歷它的成員。
ws.size // undefined ws.forEach // undefined ws.forEach(function(item){ console.log('WeakSet has ' + item)}) // TypeError: undefined is not a function
上面代碼試圖獲取size和forEach屬性,結果都不能成功。
WeakSet 不能遍歷,是由於成員都是弱引用,隨時可能消失,遍歷機制沒法保證成員的存在,極可能剛剛遍歷結束,成員就取不到了。WeakSet 的一個用處,是儲存 DOM 節點,而不用擔憂這些節點從文檔移除時,會引起內存泄漏。
參考:
Learning Javascript Data Structures and Algorithms
推薦一個找vue,angular組件的輪子工廠
前端面試總結--數據結構與算法一
前端面試總結--數據結構與算法二
前端面試總結--數據結構與算法三
前端面試總結--數據結構與算法四