文章结构

  • 集合的定义
  • 集合的实现


集合的定义

集合是由一组无序且唯一(即不能重复)的项组成的。这个数据结构使用了与有限集合相同
的数学概念。
JavaScript的对象不允许一个键 指向两个不同的属性,保证了集合里的元素都是唯一的。
因此我们基于对象实现集合这种数据结构,将对象中的属性名等于属性值就可以存储数据了

集合的实现

// 集合
export default function() {
    this.items = {};

    // 这么写,创建多个集合时,用的都是一个对象
    // let items = {};

    // 判断集合中是否有某个属性,返回布尔值
    this.__proto__.has = function(value) {
        return this.items.hasOwnProperty(value);
    };

    // 向集合中添加属性
    this.__proto__.add = function(value) {
        if (!this.has(value)) {
            this.items[value] = value;
            return true;
        }
        return false;
    };

    // 在集合中删除某个值
    this.__proto__.remove = function(value) {
        if (this.has(value)) {
            delete this.items[value];
            return true;
        }
        return false;
    };

    // 清空集合,删除集合所有的值
    this.__proto__.clear = function() {
        this.items = {};
        return true;
    };

    // 返回集合的长度,不用考虑兼容性的写法
    /*不能简单地使用for- in语句遍历items对象的属性,递增count变量的值。还需要使用has方法(以验证items对象具有该属性),因为对象的原型包含了额外的属性( 属性既有继承自JavaScript的object类的,也有属于对象自身,未用于数据结构的)。
     */
    this.__proto__.size = function() {
        // 计数器
        let count = 0;
        for (let prop in this.items) {
            if (this.has(prop)) {
                count++;
            }
        }
        return count;
    };

    // 以数组的形式返回集合中所有的元素
    this.__proto__.valuesArr = function() {
        let arr = [];
        for (let prop in this.items) {
            if (this.items.hasOwnProperty(prop)) {
                arr.push(this.items[prop]);
            }
        }
        return arr;
    };

    // 求与另外一个集合的并集
    this.__proto__.union = function(set2) {
        // for(var i in arr)i是数组的下标
        // for(var i in obj)i是对象的属性名
        // 可以通过items[属性名]调用属性值判断是否相同,在这里我们利用之前的valuesArr()方法转数组,通过下标调用数组值也可行
        let arr1 = this.valuesArr();
        let arr2 = set2.valuesArr();
        /* 方式1:返回一个普通的对象
            let obj = {};
            // 深拷贝原始集合, 防止调用方法, 破坏原始集合
            for (let prop in this.items) {
                obj[prop] = this.items[prop];
            }
            // 查询与原集合不同的值
            for (let prop2 in arr2) {
                for (let prop1 in arr1) {
                    if (arr2[prop2] !== arr1[prop1]) {
                        obj[arr2[prop2]] = arr2[prop2];
                    }
                }
            } */

        /* 方式2:返回一个集合
         */
        let obj = new LJCustomSet();
        for (let prop in this.items) {
            obj.add(this.items[prop]);
        }
        // 查询与原集合不同的值
        for (let prop2 in arr2) {
            for (let prop1 in arr1) {
                if (arr2[prop2] !== arr1[prop1]) {
                    obj.add(arr2[prop2]);
                }
            }
        }
        return obj;
    };

    // 求与另外一个集合的交集
    this.__proto__.intersection = function(set2) {
        // for(var i in arr)i是数组的下标
        // for(var i in obj)i是对象的属性名
        let arr1 = this.valuesArr();
        let arr2 = set2.valuesArr();
        // 存放交集
        /* 方式1 
            let obj = {}
                // 查询不同的值
            for (let prop2 in arr2) {
                for (let prop1 in arr1) {
                    if (arr2[prop2] == arr1[prop1]) {
                        obj[arr1[prop1]] = arr1[prop1];
                        // 匹配上了,后面的必不可能相同,不然set2就不是集合了,因此退出当前循环
                        break;
                    }
                }
            } */

        /* 方式2: 返回一个集合 */
        let obj = new LJCustomSet();
        for (let prop2 in arr2) {
            for (let prop1 in arr1) {
                if (arr2[prop2] == arr1[prop1]) {
                    obj.add(arr1[prop1]);
                    // 匹配上了,后面的必不可能相同,不然set2就不是集合了,因此退出当前循环
                    break;
                }
            }
        }
        return obj;
    };

    // 求与另外一个集合的差集,找到当前集合不同于另外一个集合的属性值,找“我有你没有的”
    this.__proto__.differenceSet = function(set2) {
        let arr1 = this.valuesArr();
        let arr2 = set2.valuesArr();
        /* 方式1
            let obj = {};
            // 去掉相同的值
            for (let prop1 in arr1) {
                for (let prop2 in arr2) {
                    if (arr2[prop2] == arr1[prop1]) {
                        // 这个数组是通过集合转换而来的,不会有重复的值
                        arr1.splice(arr1.indexOf(arr1[prop1]), 1);
                        // 将arr2中重复的值也删掉,减少后续for循环执行的次数
                        arr2.splice(arr2.indexOf(arr2[prop2], 1));
                        // 退出当前的循环,只会退出一个for循环
                        break;
                    }
                }
            } 
            // 剩下来的独一无二的属性值
            for (let prop in arr1) {
                obj[arr1[prop]] = arr1[prop];
            }*/

        /* 方式2: 返回一个集合 */
        let obj = new LJCustomSet();
        // 去掉相同的值
        for (let prop1 in arr1) {
            for (let prop2 in arr2) {
                if (arr2[prop2] == arr1[prop1]) {
                    // 这个数组是通过集合转换而来的,不会有重复的值
                    arr1.splice(arr1.indexOf(arr1[prop1]), 1);
                    // 将arr2中重复的值也删掉,减少后续for循环执行的次数
                    arr2.splice(arr2.indexOf(arr2[prop2], 1));
                    // 退出当前的循环,只会退出一个for循环
                    break;
                }
            }
        }

        for (let prop in arr1) {
            obj.add(arr1[prop]);
        }

        return obj;
    };

    // 判断当前集合是不是另外一个集合的子集
    this.__proto__.Subject = function(set2) {
        let arr1 = this.valuesArr();
        let arr2 = set2.valuesArr();
        if (arr1.length <= arr2.length) {
            for (let prop1 in arr1) {
                for (let prop2 in arr2) {
                    // 在当前这次循环次数中,不相等判断prop2是不是arr2的最后一个下标,如果是就说明当前arr1[prop1]在arr2中找不到,所以就不是
                    if (arr1[prop1] !== arr2[prop2]) {
                        if (prop2 == arr2.length - 1) {
                            return false;
                        }
                    } else {
                        break;
                    }
                }
            }
            return true;
        } else {
            return false;
        }
    };
};