讀古今文學網 > 學習JavaScript數據結構與算法(第2版) > 6.3 集合操作 >

6.3 集合操作

對集合可以進行如下操作。

  • 並集:對於給定的兩個集合,返回一個包含兩個集合中所有元素的新集合。

  • 交集:對於給定的兩個集合,返回一個包含兩個集合中共有元素的新集合。

  • 差集:對於給定的兩個集合,返回一個包含所有存在於第一個集合且不存在於第二個集合的元素的新集合。

  • 子集:驗證一個給定集合是否是另一集合的子集。

6.3.1 並集

並集的數學概念是集合A和集合B的並集,表示為:

AB

該集合定義如下:

AB = { x | xAˇxB }

意思是x(元素)存在於A中,或x存在於B中。下圖展示了並集操作:

現在來實現Set類的union方法:

this.union = function(otherSet){
  let unionSet = new Set; //{1}

  let values = this.values; //{2}
  for (let i=0; i<values.length; i++){
    unionSet.add(values[i]);
  }

  values = otherSet.values; //{3}
  for (let i=0; i<values.length; i++){
    unionSet.add(values[i]);
  }

  return unionSet;
};

  

首先需要創建一個新的集合,代表兩個集合的並集(行{1})。接下來,獲取第一個集合(當前的Set類實例)所有的值(values),遍歷並全部添加到代表並集的集合中(行{2})。然後對第二個集合做同樣的事(行{3})。最後返回結果。

測試一下上面的代碼:

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\"]。注意元素3同時存在於AB中,它在結果的集合中只出現一次。

6.3.2 交集

交集的數學概念是集合A和集合B的交集,表示為:

AB

該集合定義如下:

AB = { x | xAΛxB }

意思是x(元素)存在於A中,且x 存在於B中。下圖展示了交集操作:

現在來實現Set類的intersection方法:

this.intersection = function(otherSet){
  let intersectionSet = new Set; //{1}

  let values = this.values;
  for (let i=0; i<values.length; i++){ //{2}
    if (otherSet.has(values[i])){    //{3}
      intersectionSet.add(values[i]); //{4}
    }
  }

  return intersectionSet;
}

  

intersection方法需要找到當前Set實例中,所有也存在於給定Set實例中的元素。首先創建一個新的Set實例,這樣就能用它返回共有的元素(行{1})。接下來,遍歷當前Set實例所有的值(行{2}),驗證它們是否也存在於otherSet實例(行{3})之中。可以用這一章前面實現的has方法來驗證元素是否存在於Set實例中。然後,如果這個值也存在於另一個Set實例中,就將其添加到創建的intersectionSet變量中(行{4}),最後返回它。

做些測試:

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 intersectionAB = setA.intersection(setB);
console.log(intersectionAB.values);

  

輸出為[\"2\", \"3\"],因為23同時存在於兩個集合中。

6.3.3 差集

差集的數學概念是集合A和集合B的差集,表示為:A-B,定義如下:

A-B = { x | xA Λ xB }

意思是x(元素)存在於A中,且x不存在於B 中。下圖展示了集合AB 的差集操作:

現在來實現Set類的difference方法:

this.difference = function(otherSet){
  let differenceSet = new Set; //{1}

  let values = this.values;
  for (let i=0; i<values.length; i++){ //{2}
    if (!otherSet.has(values[i])){   //{3}
      differenceSet.add(values[i]); //{4}
    }
  }

  return differenceSet;
};

 

intersection方法會得到所有同時存在於兩個集合中的值。而difference方法會得到所有存在於集合A但不存在於B的值。因此這兩個方法在實現上唯一的區別就是行{3}。只獲取不存在於otherSet實例中的值,而不是也存在於其中的值。行{1}{2}{4}是完全相同的。

(用跟intersection部分相同的集合)做些測試:

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 differenceAB = setA.difference(setB);
console.log(differenceAB.values);

  

輸出為[\"1\"],因為1是唯一一個僅存在於setA的元素。

6.3.4 子集

我們要介紹的最後一個集合操作是子集。子集的數學概念是集合A是集合B的子集(或集合B包含了A),表示為:

AB

該集合定義如下:

x { xAxB }

意思是集合A中的每一個x(元素),也需要存在於B 中。下圖展示了集合A是集合B 的子集:

現在來實現Set類的subset方法:

this.subset = function(otherSet){

  if (this.size > otherSet.size){ //{1}
    return false;
  } else {
    let values = this.values;
    for (let i=0; i<values.length; i++){ //{2}
      if (!otherSet.has(values[i])){ //{3}
        return false; //{4}
      }
    }
    return true; //{5}
  }
};

  

首先需要驗證的是當前Set實例的大小。如果當前實例中的元素比otherSet實例更多,它就不是一個子集(行{1})。子集的元素個數需要小於或等於要比較的集合。

接下來要遍歷集合中的所有元素(行{2}),驗證這些元素也存在於otherSet中(行{3})。如果有任何元素不存在於otherSet中,就意味著它不是一個子集,返回false(行{4})。如果所有元素都存在於otherSet中,行{4}就不會被執行,那麼就返回true(行{5})。

檢驗一下上面的代碼效果如何:

let setA = new Set;
setA.add(1);
setA.add(2);

let setB = new Set;
setB.add(1);
setB.add(2);
setB.add(3);

let setC = new Set;
setC.add(2);
setC.add(3);
setC.add(4);

console.log(setA.subset(setB));
console.log(setA.subset(setC));

  

我們有三個集合:setAsetB的子集(因此輸出為true),然而setA不是setC的子集(setC只包含了setA中的2,而不包含1),因此輸出為false