小言_互联网的博客

【数据结构与算法】详解什么是集合,并用代码手动实现一个集合结构

494人阅读  评论(0)

本系列文章【数据结构与算法】所有完整代码已上传 github,想要完整代码的小伙伴可以直接去那获取,可以的话欢迎点个Star哦~下面放上跳转链接

集合这个概念应该大家在学习数学的时候都听过并且有学习过,它也是一种数据结构,我们还是需要用代码来实现集合的很多方法。

学习过ES6语法的小伙伴应该知道,ES6新增了一种 Set 数据结构,这就是集合,尽管官方已经向我们提供了这种数据结构,但是为了学习它的思想和实现过程,我们还是来亲自学习实现一下吧,顺便学习一下ES6中 Set 数据结构是如何实现的

公众号:Lpyexplore的编程小屋
关注我,每天更新,带你在python爬虫的过程中学习前端,还有更多电子书面试题数据结构与算法代码等你来拿


一、什么是集合

集合就是一种包含着不同元素的数据结构,即在集合结构里,每一个元素都是独一无二的,互不相同,同时所有数据都是无序的。

如图中的每个圆圈就代表一个集合,集合中存储着相应的数据

其中,集合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 作为参数

实现思路:

  1. 先创建一个空的新集合 newSet
  2. 通过 values() 方法获取到包含当前集合的所有元素的数组 oldSetValue,并对其进行遍历,将遍历到每一个元素都添加到 newSet() 中去
  3. 再通过 values() 方法获取到包含 otherSet 的所有元素的数组 otherSetValue,并对其进行遍历,将遍历到每一个元素都添加到 newSet() 中去
  4. 返回 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 作为参数

实现思路:

  1. 先创建一个空的新集合 newSet
  2. 通过 values() 方法获取到包含当前集合的所有元素的数组 oldSetValue,并对其进行遍历,判断每一个元素是否也存在于 otherSet 中,若不存在,则不做任何处理
  3. 若存在,则将该元素添加到 newSet 中去
  4. 返回 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 作为参数

实现思路:

  1. 先创建一个空的新集合 newSet
  2. 通过 values() 方法获取到包含当前集合的所有元素的数组 oldSetValue,并对其进行遍历,判断每一个元素是否也存在于 otherSet 中,若存在,则不做任何处理
  3. 若不存在,则将该元素添加到 newSet 中去
  4. 返回 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 作为参数

实现思路:

  1. 先创建一个空的新集合 newSet
  2. 通过 values() 方法获取到包含当前集合的所有元素的数组 oldSetValue,并对其进行遍历,判断每一个元素是否也存在于 otherSet 中,若不存在,则直接返回 false,表示当前集合不是 otherSet 的子集
  3. 若所有元素遍历完后,该方法仍为返回任何值,此时直接返回 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

我是Lpyexplore,创作不易,喜欢的加个关注,点个收藏,给个赞~ 带你们在Python爬虫的过程中学习Web前端


转载:https://blog.csdn.net/l_ppp/article/details/108298145
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场