用js來實現那些數據結構10(集合02-集合的操作)
前一篇文章我們一起實現了自定義的set集合類。那麽這一篇我們來給set類增加一些操作方法。那麽在開始之前,還是有必要解釋一下集合的操作有哪些。便於我們更快速的理解代碼。
1、並集:對於給定的兩個集合,返回一個包含兩個集合中所有元素的新集合。註意,集合中不會有重復的值。
2、交集:對於給定的兩個集合,返回一個包含兩個集合中共有元素的新集合。
3、差集:對於給定的集合,返回一個包含所有存在於第一個集合且不存在於第二個集合的元素的新集合。簡單來說就是我有你沒有的元素。
4、驗證一個給定集合是否是另一個集合的子集。
這裏我們就不詳細的再贅述一遍集合操作的數學計算方法了。有興趣或者忘記了的小夥伴可以百度一下。那麽咱們就正式開始集合的操作方法。
一、並集
//並集操作
this.union = function (otherSet) {
//存儲兩個集合元素的新集合,後面我們會把它作為返回值返回。
let unionSet = new Set();
//values為當前set的數組列表
let values = this.values();
//循環加入
for(let i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
//重新復制values
values = otherSet.values();
//把otherSet的值循環存入unionSet,由於我們的add不會加入重復的值,自然在unionSet中就不會出現重復的值
for(let i = 0; i < values.length; i++) {
unionSet.add(values[i]);
}
return unionSet;
}
我們發現,其實並集的操作十分簡單,就是聲明一個新的set,然後通過循環兩個setA和setB中的值存入新的unionSet中就可以了。一點都不復雜
let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
let setB = new Set();
setB.add(3);
setB.add(4);
setB.add(5);
setB.add(6);
let unionAB = setA.union(setB);
console.log(unionAB.values());// [1, 2, 3, 4, 5, 6]
二、交集
//交集操作
this.intersection = function (otherSet) {
let intersectionSet = new Set();
let values = this.values();
for (let i = 0; i < values.length; i++) {
if(otherSet.has(values[i])) {
intersectionSet.add(values[i])
}
}
return intersectionSet;
}
交集操作其實十分簡單,一句話就是檢查setA中的元素是否在setB中也有,如果有那麽久存入intersectionSet中。就跟我們要查找兩個數組中是否有相同的元素是一個道理。
let setC = new Set();
setC.add(5);
setC.add(6);
setC.add(7);
let setD = new Set();
setD.add(5);
setD.add(7);
setD.add(4);
setD.add(8);
let intersectionSetCD = setC.intersection(setD);
console.log(intersectionSetCD.values());//[5,7]
三、差集
//差集操作
this.difference = function (otherSet) {
let differenceSet = new Set();
let values = this.values();
for (let i = 0; i < values.length; i++) {
//只是比交集操作這裏的判斷改成了非(!)而已
if(!otherSet.has(values[i])) {
differenceSet.add(values[i])
}
}
return differenceSet;
}
差集的操作和並集的操作十分類似。並集是需要兩個集合中都存在的元素(你有我也有),而差集是存在於setA中但是不存在於setB中(你有我沒有)。
所以我們只需要稍微更改一下交集的代碼就可以了。
let setM = new Set();
setM.add(5);
setM.add(6);
setM.add(7);
let setN = new Set();
setN.add(5);
setN.add(7);
setN.add(4);
setN.add(8);
let differenceSetMN = setM.difference(setN);
console.log(differenceSetMN.values());//[6]
四、子集
//子集操作
this.subset = function (otherSet) {
if(this.size() > otherSet.size()) {
return false;
} else {
let values = this.values();
for (let i = 0; i < values.length; i++) {
if(!otherSet.has(values[i])) {
return false;
}
}
return true;
}
}
其實子集操作也沒什麽好解釋的,只是要註意的是如果setA的子集是setB,那麽setA的元素個數是一定大於或等於setB的。否則setB就不可能是setA的子集。所以我們在最開始就判斷元素的size是否符合這個定義。
那麽如果符合,我們在遍歷整個setB的元素,判斷在setA中是否存在,只要有不存在的就直接返回false,如果遍歷結束都存在,那麽才返回true。
let setX = new Set();
setX.add(1);
setX.add(2);
let setY= new Set();
setY.add(1);
setY.add(2);
setY.add(3);
let setZ= new Set();
setZ.add(2);
setZ.add(3);
setZ.add(4);
console.log(setX.subset(setY));//true
console.log(setX.subset(setZ));//false
這裏我們就介紹完了集合的操作,是不是十分簡單。那麽接下來我們來看看ES6原生的set類是什麽樣子的。
ES6原生Set類
我們先來看看原生set類的簡單例子:
let set = new Set();
set.add(1);
console.log(set.values());//SetIterator {1}
set.add(2);
console.log(set.has(1));//true
console.log(set.size)//2
console.log(set.delete(1));//true
console.log(set.size)//1
console.log(set.has(1));//false
console.log(set.has(2));//true
原生Set類擁有has()、add()、delete()、clear()等方法。也擁有values()、keys()、entries()、forEach()等遍歷方法,還擁有一個size屬性。這裏不會詳細的介紹每一個屬性方法,想要深入學習大家可以自行去查閱。
那麽我們看看如何用原生Set類來操作集合。
let setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);
let setB = new Set();
setB.add(2);
setB.add(3);
setB.add(4);
//模擬並集操作
let unionAb = new Set();
//其實跟我們自定義並集操作的原理是一樣的,分別遍歷兩個集合並把其元素加入到unionAb中
//for...of 這種操作也是ES6的循環遍歷方法。
for (let x of setA) unionAb.add(x);
for (let x of setB) unionAb.add(x);
console.log(unionAb.values())//SetIterator {1, 2, 3, 4}
//模擬交集操作
//模擬交集操作需要創建一個輔助函數,來生成包含setA和setB都有的元素的新集合。
let intersetion = function (setA,setB) {
let intersetionSet = new Set();
for(let x of setA) {
if(setB.has(x)) {
intersetionSet.add(x);
}
}
return intersetionSet;
}
let intersetionAb = intersetion(setA,setB);
console.log(intersetionAb.values())//SetIterator {2, 3}
//模擬差集操作
//同樣的,跟交集操作極為類似,只是判斷條件剛好相反罷了
let difference = function (setA,setB) {
let differenceSet = new Set();
for(let x of setA) {
if(!setB.has(x)) {
differenceSet.add(x);
}
}
return differenceSet;
}
let differenceAb = difference(setA,setB);
console.log(differenceAb.values())//SetIterator {1}
在寫完了ES6原生Set類模擬集合操作的時候,我們發現跟我們自定義的集合操作方法極為相似。只是我們使用了ES6原生的接口罷了。大家可以嘗試著對比一下這兩種類型的代碼。加深印象。
到這裏集合就介紹完畢了。回顧一下代碼,我們發現其實集合的各種操作方法在我們的實際工作中也是經常應用到的,只是我們在用數組操作,並沒有十分的去註意這些細節。比如並集操作,我們在合並兩個數組的時候肯定用到過。比如交集操作,我們在查找兩個數組中公共元素的時候就會用到。所以其實我們在工作中已經用過或者說經常使用這些類似於集合操作的思想。
最後,由於本人水平有限,能力與大神仍相差甚遠,若有錯誤或不明之處,還望大家不吝賜教指正。非常感謝!
用js來實現那些數據結構10(集合02-集合的操作)