本系列文章【資料結構與演算法】所有完整代碼已上傳 github,想要完整代碼的小伙伴可以直接去那獲取,可以的話歡迎點個Star哦~下面放上跳轉鏈接
- https://github.com/Lpyexplore/structureAndAlgorithm-JS
集合這個概念應該大家在學習數學的時候都聽過并且有學習過,它也是一種資料結構,我們還是需要用代碼來實作集合的很多方法,
學習過ES6語法的小伙伴應該知道,ES6新增了一種 Set 資料結構,這就是集合,盡管官方已經向我們提供了這種資料結構,但是為了學習它的思想和實作程序,我們還是來親自學習實作一下吧,順便學習一下ES6中 Set 資料結構是如何實作的
公眾號:Lpyexplore的編程小屋
關注我,每天更新,帶你在python爬蟲的程序中學習前端,還有更多電子書、面試題、資料結構與演算法代碼等你來拿

資料結構——集合
- 一、什么是集合
- 二、集合分類
- (1)交集
- (2)并集
- (3)差集
- (4)子集
- 三、集合的方法
- 四、用代碼實作集合
- (1)創建一個建構式
- (2)實作has()方法
- (3)實作add()方法
- (4)實作delete()方法
- (5)實作clear()方法
- (6)實作size()方法
- (7)實作values()方法
- (8)實作union()方法
- (9)實作intersect()方法
- (10)實作difference()方法
- (11)實作subset()方法
- 五、結束語
一、什么是集合
集合就是一種包含著不同元素的資料結構,即在集合結構里,每一個元素都是獨一無二的,互不相同,同時所有資料都是無序的,
如圖中的每個圓圈就代表一個集合,集合中存盤著相應的資料

其中,集合1 和 集合2 中同樣是存盤著資料 1 2 3 4,但分布情況卻不同,這說明集合的無序性,而且 集合1 與 集合2并不相等
二、集合分類
集合也有幾種特殊的分類,即 并集 、交集 、差集 、子集,其展示的是兩個集合之間的關系
(1)交集
交集就是由既屬于 集合1 又屬于 集合2 的元素組成的集合,
如圖

集合1中有資料 1 4
集合2中有資料 2 3 5 8
那么 集合1 與 集合2 所有元素組合起來就是 1 2 3 4 5 8·,這些元素組合起來就組成了新集合 集合3,也稱 集合3 為 集合1 與 集合2 的交集
(2)并集
并集: 由所有屬于 集合1 和 集合2 的元素組成的集合
如圖

集合1中有資料 1 2 4 5
集合2中有資料 1 2 3 4 5
那么既屬于 集合1 又屬于 集合2 的元素就是 1 2 4,因此這幾個元素就組合成了新的集合 集合3,也稱為 集合1 與 集合2 的并集
(3)差集
差集: 就是屬于 集合1 但不屬于 集合2 的所有元素組成的集合
如圖

集合1中有資料 1 2 4
集合2中有資料 1 3 5 8
那么屬于 集合1 但不屬于 集合2 的元素就是 2 4,這兩個元素組成了新的集合 集合3,也稱 集合3 為 集合1 與 集合2 的差集
(4)子集
子集: 是判斷屬于 集合1 的元素是否也都屬于 集合2
如圖

集合1中有資料 1 2 4
集合2中有資料 1 2 3 4 5 8
此時因為 集合1 中的所有元素同時也屬于 集合2,所以說 集合1 是 集合2 的子集,也可以說是 集合1 屬于 集合2
三、集合的方法
了解了以上這些集合的概念,接下來我們來看一下封裝一個集合,都有哪些方法,
首先一個資料結構,必備的增刪改查方法是肯定需要的,其次我們盡可能地與ES6的 Set 資料結構中的方法一致,這樣方便大家之后學習
| 方法 | 作用 |
|---|---|
| add() | 將一個資料添加到集合中 |
| has() | 判斷一個元素是否存在于集合中 |
| delete() | 洗掉集合中的某個元素 |
| clear() | 清空集合內的所有元素 |
| size() | 回傳集合內的元素個數 |
| values() | 回傳集合內的所有元素,保存在陣列中 |
| union() | 獲取與另一個集合的交集 |
| intersect() | 獲取與另一個集合的并集 |
| difference() | 獲取與另一個集合的差集 |
| subset() | 判斷是否為另一個集合的子集 |
四、用代碼實作集合
(1)創建一個建構式
首先創建一個大的建構式,用于存放集合的一些屬性和方法,
function Set() {
// 屬性
this.items = {}
}
屬性 items 用于存放集合中的元素,這里之所以使用物件來存盤而不是陣列,是因為陣列若實作無重復資料很麻煩,需要遍歷全部元素,而物件就很方便,直接通過 key 就能獲取到集合中是否已存在該資料
(2)實作has()方法
has() 方法是用于判斷集合中是否存在某資料,該方法接收一個引數 value 用于查找資料
這里先介紹一個JS中物件的內置方法:
hasOwnProperty() 方法可以判斷某屬性是否為物件的自有屬性,若是,則回傳 true ;否則回傳 false
所以實作思路就很簡單了,直接將引數 value 傳給 hasOwnProperty() 方法,并將其回傳結果作為 has() 方法的回傳結果即可
我們來看一下代碼吧
function Set() {
// 屬性
this.items = {}
// 方法
// 判斷是否存在元素
Set.prototype.has = function(value) {
return this.items.hasOwnProperty(value)
}
}
因為這里我們還沒有介紹到 add() 方法,因此還沒法驗證該方法是否可行,而且之后我們會在別的方法中頻繁用到 has() 方法用于驗證集合中元素是否重復,這里就不做過多的驗證了
(3)實作add()方法
add() 方法是用于向集合中添加資料,并回傳當前集合,該方法接收一個引數 value 用于存盤
實作思路很簡單,先通過我們封裝的 has()方法 判斷集合中是否存在該元素,若存在,則直接回傳 false ;否則直接通過 obj[key] = value 的方式存盤即可,這里我們是將引數 value 既作為 key 又作為 value
來看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 添加元素
Set.prototype.add = function(value) {
// 判斷是否存在重復元素
if(this.has(value)) return false;
// 存盤元素
this.items[value] = value
// 回傳當前集合內容
return this.items
}
}
我們來使用一下該方法
let set = new Set()
set.add(3)
set.add(1)
set.add(6)
console.log(set.items)
/* 列印結果:
{
'1': 1,
'3': 3,
'6': 6
}
*/
可以看到,我們三個添加資料的操作都成功了
(4)實作delete()方法
delete() 方法就是用于洗掉集合中指定的元素,該方法接收一個引數 value 用于查找到對應的元素并洗掉
實作思路很簡單,先通過 has() 方法判斷集合中是否存在該元素,若不存在,則直接回傳 false ,表示洗掉失敗 ;否則,直接用關鍵字 delete 洗掉集合中對應的元素,并回傳 true 表示洗掉成功
我們來看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 洗掉元素
Set.prototype.delete = function(value) {
// 判斷集合中是否存在該元素
if(!this.has(value)) return false;
// 洗掉指定元素
delete this.items[value]
// 回傳 true,表示洗掉成功
return true
}
}
我們來使用一下該方法
let set = new Set()
// 添加三個元素,分別為 3 1 6
set.add(3)
set.add(1)
set.add(6)
// 洗掉元素 6
set.delete(6)
console.log(set.items)
/* 列印結果:
{
'1': 1,
'3': 3
}
*/
我們可以看到,6 成功被洗掉了
(5)實作clear()方法
clear() 方法時用于清空集合中的所有元素的,該方法無需傳入引數
實作思路: 直接將 this.items 指向一個空的物件即可
我們看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 清空集合
Set.prototype.clear = function() {
this.items = {}
}
}
來使用一下該方法
let set = new Set()
// 添加三個元素,分別為 3 1 6
set.add(3)
set.add(1)
set.add(6)
// 清空集合
set.clear()
console.log(set.items)
/* 列印結果:
{}
*/
我們可以看到,集合中的所有元素已經被清空了
(6)實作size()方法
size() 方法就是回傳集合中的元素個數,該方法無需傳入引數
這里先介紹一個JS中物件的內置方法:
keys()方法可以接收一個物件引數,并回傳該物件所有的鍵,存放在一個陣列中并回傳
實作思路: 通過 keys() 獲取包含集合所有鍵的陣列,并回傳該陣列的 length 即可
我們來看一下代碼吧
function Set() {
// 屬性
this.items = {}
// 方法
// 判斷集合內元素個數
Set.prototype.size = function() {
return Object.keys(this.items).length
}
}
來使用一下該方法
let set = new Set()
console.log(set.size()) // 0,此時集合為空
// 添加三個元素,分別為 3 1 6
set.add(3)
set.add(1)
set.add(6)
console.log(set.size()) // 3,此時集合內有三個元素
(7)實作values()方法
values() 方法是用于回傳集合中的所有元素,該方法無需傳入任何引數
實作思路: 直接將通過方法 keys() 獲取到的陣列回傳即可
我們來看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 回傳集合內所有元素
Set.prototype.values = function() {
return Object.keys(this.items)
}
}
我們來使用一下該方法
let set = new Set()
console.log(set.values()) // [],此時集合為空
// 添加三個元素,分別為 3 1 6
set.add(3)
set.add(1)
set.add(6)
console.log(set.values()) // ['1', '3', '6'],此時集合內有三個元素,分別為 1 、3 、6
(8)實作union()方法
union() 方法用于獲取當前集合與另一個集合的交集,該方法需要傳入一個集合 otherSet 作為引數
實作思路:
- 先創建一個空的新集合
newSet - 通過
values()方法獲取到包含當前集合的所有元素的陣列oldSetValue,并對其進行遍歷,將遍歷到每一個元素都添加到newSet()中去 - 再通過
values()方法獲取到包含otherSet的所有元素的陣列otherSetValue,并對其進行遍歷,將遍歷到每一個元素都添加到newSet()中去 - 回傳
newSet
在該實作程序中,我們是通過 add() 方法將兩個集合中的所有元素添加到新的集合中的,因為 add() 方法中已經包含了檢驗元素的重復性部分,所以我們無需擔心兩個集合的元素是否會重復
我們來看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 獲取交集
Set.prototype.union = function(otherSet) {
// 1. 創建新的空集合
let newSet = new Set()
// 2. 獲取當前集合的所有元素
let oldSetValue = this.values()
// 2.1 遍歷當前集合的元素,并添加到 newSet中
for(let i = 0; i < oldSetValue.length; i++) {
newSet.add(oldSetValue[i])
}
// 3. 獲取 otherSet集合的所有元素
let otherSetValue = otherSet.values()
// 3.1 遍歷 otherSet集合的元素,并添加到 newSet中
for(let j = 0; j < otherSetValue.length; j++) {
newSet.add(otherSetValue[j])
}
// 4. 回傳獲取到的交集
return newSet
}
}
我們來使用一下該方法
// 創建集合1
let set1 = new Set()
// 向集合1中添加元素 3 1 6
set1.add(3)
set1.add(1)
set1.add(6)
// 創建集合2
let set2 = new Set()
// 向集合2中添加元素 3 2 8
set2.add(3)
set2.add(2)
set2.add(8)
// 獲取集合1和集合2的交集,即集合3
let set3 = set1.union(set2)
// 查看集合3內的所有元素
console.log(set3.values())
/* 列印結果:
[ '1', '2', '3', '6', '8' ]
*/
(9)實作intersect()方法
intersect() 方法是用于獲取當前集合與另一個集合的并集,該放需要傳入一個集合 otherSet 作為引數
實作思路:
- 先創建一個空的新集合
newSet - 通過
values()方法獲取到包含當前集合的所有元素的陣列oldSetValue,并對其進行遍歷,判斷每一個元素是否也存在于otherSet中,若不存在,則不做任何處理 - 若存在,則將該元素添加到
newSet中去 - 回傳
newSet
我們來看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 獲取并集
Set.prototype.intersect = function(otherSet) {
// 1. 創建空的新集合
let newSet = new Set()
// 2. 獲取當前集合的所有元素
let oldSetValue = this.values()
// 3. 遍歷當前集合的所有元素
for(let i = 0; i < oldSetValue.length; i++) {
let item = oldSetValue[i]
// 3.1 元素同時存在于 otherSet中
if(otherSet.has(item)) {
newSet.add(item)
}
}
// 4. 回傳獲取到的并集
return newSet
}
}
我們來使用一下該方法
// 創建集合1
let set1 = new Set()
// 向集合1中添加元素 3 1 6
set1.add(3)
set1.add(1)
set1.add(6)
// 創建集合2
let set2 = new Set()
// 向集合2中添加元素 3 2 8
set2.add(3)
set2.add(2)
set2.add(8)
// 獲取集合1和集合2的并集,即集合3
let set3 = set1.intersect(set2)
// 查看集合3內的所有元素
console.log(set3.values())
/* 列印結果:
[ '3' ]
*/
(10)實作difference()方法
difference() 方法是用于獲取當前集合與另一個集合的差集,該放需要傳入一個集合 otherSet 作為引數
實作思路:
- 先創建一個空的新集合
newSet - 通過
values()方法獲取到包含當前集合的所有元素的陣列oldSetValue,并對其進行遍歷,判斷每一個元素是否也存在于otherSet中,若存在,則不做任何處理 - 若不存在,則將該元素添加到
newSet中去 - 回傳
newSet
我們來看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 獲取差集
Set.prototype.difference = function(otherSet) {
// 1. 創建空的新集合
let newSet = new Set()
// 2. 獲取當前集合的所有元素
let oldSetValue = this.values()
// 3. 遍歷當前集合的所有元素
for(let i = 0; i < oldSetValue.length; i++) {
let item = oldSetValue[i]
// 3.1 otherSset中沒有該元素
if(!otherSet.has(item)) {
newSet.add(item)
}
}
// 4. 回傳獲取到的差集
return newSet
}
}
我們來使用一下該方法
// 創建集合1
let set1 = new Set()
// 向集合1中添加元素 3 1 6
set1.add(3)
set1.add(1)
set1.add(6)
// 創建集合2
let set2 = new Set()
// 向集合2中添加元素 3 2 8
set2.add(3)
set2.add(2)
set2.add(8)
// 獲取集合1和集合2的差集,即集合3
let set3 = set1.difference(set2)
// 查看集合3內的所有元素
console.log(set3.values())
/* 列印結果:
[ '1', '6' ]
*/
(11)實作subset()方法
subset() 方法用于判斷當前集合是否為另一個集合的子集,該方法需要傳入一個集合 otherSet 作為引數
實作思路:
- 先創建一個空的新集合
newSet - 通過
values()方法獲取到包含當前集合的所有元素的陣列oldSetValue,并對其進行遍歷,判斷每一個元素是否也存在于otherSet中,若不存在,則直接回傳false,表示當前集合不是otherSet的子集 - 若所有元素遍歷完后,該方法仍為回傳任何值,此時直接回傳
true,表示當前集合為otherSet的子集
我們來看一下代碼
function Set() {
// 屬性
this.items = {}
// 方法
// 判斷是否為另一個集合的子集
Set.prototype.subset = function(otherSet) {
// 1. 創建空的新集合
let oldSetValue = this.values()
for(let i = 0; i < oldSetValue.length; i++) {
if(!otherSet.has(oldSetValue[i])) {
return false
}
}
return true
}
}
我們來是用一下該方法
// 創建集合1
let set1 = new Set()
// 向集合1中添加元素 3 1
set1.add(3)
set1.add(1)
// 創建集合2
let set2 = new Set()
// 向集合2中添加元素 3 2 8 1 9
set2.add(3)
set2.add(2)
set2.add(8)
set2.add(1)
set2.add(9)
// 判斷集合1是否為集合2的子集
let ret = set1.subset(set2)
// 查看集合3內的所有元素
console.log(ret)
// 列印結果:true
五、結束語
集合的講解就到這里了,希望大家對集合有了更深一層的理解,下一篇文章我將講解一下圖,
大家可以關注我,之后我還會一直更新別的資料結構與演算法的文章來供大家學習,并且我會把這些文章放到【資料結構與演算法】這個專欄里,供大家學習使用,
然后大家可以關注一下我的微信公眾號:Lpyexplore的編程小屋,等這個專欄的文章完結以后,我會把每種資料結構和演算法的筆記放到公眾號上,大家可以去那獲取,
或者也可以去我的github上獲取完整代碼,歡迎大家點個Star
- https://github.com/Lpyexplore/structureAndAlgorithm-JS
我是Lpyexplore,創作不易,喜歡的加個關注,點個收藏,給個贊~ 帶你們在Python爬蟲的程序中學習Web前端
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/1431.html
標籤:其他
