JavaScript数据结构与算法 - 集合

2021/4/29 1:25:22

本文主要是介绍JavaScript数据结构与算法 - 集合,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1. 集合

  • 由一组无序且唯一的项组成
  • 空集:集合里没有任何元素
  • 以 [值,值] 的形式存储元素

2. 创建集合类

class Set {
    constructor() {
        this.items = {};
    }
}

这里使用对象来实现,但也可以使用数组。

JavaScript对象不允许一个键指向俩个不同的属性,保证了集合里的元素都是唯一的。

一些常用方法:

  • add(element):向集合添加一个新元素
  • delete(element):从集合移除一个元素
  • has(element):如果元素在集合中,返回true,否则返回false
  • clear():移除集合中的所有元素
  • size():返回集合所包含元素的数量
  • values():返回一个包含集合中所有值(元素)的数组

2.1 has(element)方法

has(elemenet)方法会被add、delete方法调用,先实现它。

  • 可以用JavaScript的in运算符来验证给定元素是是否是items对象的属性:
has(element) {
	return element in this.items;
}
  • 用Object的hasOwnProperty方法能更好实现:
has(element) {
    return Object.prototype.hasOwnProperty.call(this.items, element);
}
  • 第二个方法返回一个表明对象是否具有特定属性的布尔值;in运算符则返回表示对象在原型链上是否有特定属性的布尔值。
  • JavaScript中Object对象原型上的hasOwnProperty()用来判断一个属性是定义在对象本身而不是继承自原型链

2.2 add方法

add(element) {
    // 检查元素,不存在则添加到集合中
    if (!this.has(element)) {
        // 添加一个元素时,将它同时作为键和值保存,有利于查找该元素
        this.items[element] = element;
        return true;
    }
    return false;
}

2.3 delete方法

delete(element) {
    if (this.has(element)) {
        // 使用对象来存储集合的items对象,就可以简单使用delete运算符从items对象中移除属性
        delete this.items[element];
        return true;
    }
    return false;
}

2.4 clear方法

clear() {
   this.items = {};
}

移除元素可以直接将对象置空。也可以用delete方法依次移除所有元素,但没必要。


2.5 size方法

  • 方式一:使用length变量,当使用add活delete方法时就控制它
  • 方式二:使用Object类的内置方法,但只能在现代浏览器运行
// keys对象返回一个包含给定对象所有属性的数组
size() {
	return Object.keys(this.items).length;
}
  • 方式三:手动提取items的每一个属性,记录属性的个数并返回这个数,支持任何浏览器
size() {
    let count = 0;
    // 迭代items对象所有属性
    for (let key in this.items) {
        // 检查它们是否是对象自身的属性(避免重复计数
        if (this.items.hasOwnProperty(key)) {
            count++;
        }
    }
    return count;
}

2.6 values方法

// Object.values()是JavaScript7加进来的,只能部分浏览器使用
values() {
    return Object.values(this.items);
}

以下代码任何浏览器都能使用:

value() {
    let values = [];
    for (let key in this.items) {
        if (this.items.hasOwnProperty(key)) {
            values.push(key);
        }
    }
    return values;
}

2.7 使用Set类

const set = new Set();

set.add(10);
console.log(set.values());
console.log(set.has(1));
console.log(set.size());

set.add(20);
console.log(set.values());
console.log(set.has(1));
console.log(set.size());

set.delete(10);
console.log(set.values());

set.delete(20);
console.log(set.values());

在这里插入图片描述


3. 集合运算

3.1 并集

返回一个包含两个集合中所有元素的新集合。

union(otherSet) {
    // 创建一个新集合,代表两个集合的并集
    const unionSet = new Set();
    // 获取第一个集合的所有值,迭代并全部添加到并集的集合中
    this.values().forEach(value => unionSet.add(value));
    // 对第二个集合进行相同操作
    otherSet.values().forEach(value => unionSet.add(value));
    return unionSet;
}

不使用mgforEach方法和箭头函数的版本:

union(otherSet) {
    const unionSet = new Set();
    
    let values = this.values();
    for (let i = 0; i < values.length; i++) {
        unionSet.add(values[i]);
    }
    
    values = otherSet.values();
    for (let i = 0; i < values.length; i++) {
        unionSet.add(values[i]);
    }
    return unionSet
}

测试代码:

const setA = new Set();
setA.add(1);
setA.add(2);
setA.add(3);

const setB = new Set();
setB.add(3);
setB.add(4);
setB.add(5);
setB.add(6);

const unionAB = setA.union(setB);
console.log(unionAB.values());

在这里插入图片描述


3.2 交集

返回一个包含两个集合中共有元素的新集合。

intersection(otherSet) {
    const intersectionSet = new Set();
    const values = this.values();
    // 迭代当前Set实例所有的值
    for (let i = 0; i < values.length; i++) {
        // 验证它们是否也存在otherSet中
        if (otherSet.has(values[i])) {
            intersectionSet.add(values[i]);
        }
    }
    return intersectionSet;
}

测试代码:

const intersectionAB = setA.intersection(setB);
console.log(intersectionAB.values());

在这里插入图片描述

改进交集方法:

问题:假设存在以下两个集合

  • setA为 [1, 2, 3, 4, 5, 6, 7]
  • setB为 [4, 6]
    当上面的方法时,需要迭代7次setA的值,然后将这七个值和setB中的两个值比较而如果只迭代setB,就只需要两次。

解决:先比较集合大小,再迭代较小的集合

intersection(otherSet) {
    const intersectionSet = new Set();
    const values = this.values();
    const otherValues = otherSet.values();
    // 假设这个集合元素较多
    let biggerSet = values;
    // 这个集合元素较少
    let smallerSet = otherValues;
    // 比较
    if (otherValues.length = values.length > 0) {
        biggerSet = otherValues;
        smallerSet = values;
    }
    smallerSet.forEach(value => {
        if (biggerSet.includes(value)) {
            intersectionSet.add(value);
        }
    });
    return intersectionSet;
}

3.3 差集

对于给定的两个集合,返回一个包含所有存在于第一个集合且不存在于第二个集合的元素的新集合。

difference(otherSet) {
    const differenceSet = new Set();
    this.values().forEach(value => {
        if (!otherSet.has(value)) {
            differenceSet.add(value);
        }
    })
    return differenceSet;
}

注意:
不能像优化intersection方法一样优化difference方法,因为setA和setB的差集可能不同。


3.4 子集

验证一个给定集合是否是另一集合的子集。

isSubsetOf(otherSet) {
    // 当前实例的元素逼otherSet实例更多,就不是一个子集
    if (this.size() > otherSet.size()) {
        return false;
    }
    // 假定当前实例是给定集合的子集
    let isSubset = true;
    // 迭代当前集合的元素
    this.values().every(value => {
        if (!otherSet.has(value)) {
            isSubset = false;
            return false;
        }
    })
    return isSubset;
}

4. Set类

ECMAJavascript2015新增了Set类。

区别:

  1. ES2015的Set的values方法返回Iterator,而不是值构成的数组
  2. 上面实现的size()方法返回set中存储的值的个数,而ES2015的Set有一个size属性
  3. 可以用delete方法删除set中的元素
  4. clear方法会重置set数据结构,与上面实现的一样


这篇关于JavaScript数据结构与算法 - 集合的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程