数据结构——集合

集合也是一种常见的数据结构,在 ES6 中已经原生支持了这种数据结构 Set。集合是一种无序、且不能有重复元素的数据结构。
集合有如下常用操作:

  1. 添加元素
  2. 移除元素
  3. 判断元素是否存在
  4. 清空集合
  5. 获取集合的长度
  6. 获取集合的并集、交集、差集

集合的代码实现

下面是集合的代码实现,首先进行接口定义 IMySet

interface IMySet<T>{
    // 向集合中添加元素
    add(ele:T):void;
    // 从集合中移除元素
    remove(ele:T):T;
    // 判断集合中是否拥有某个元素
    has(ele:T):boolean;
    // 清空集合
    clear():void;
    // 获取集合的长度
    size():number;
    // 获取集合中的元素
    toString():T[];
    // 获取并集
    getUnionSet(newSet:IMySet<T>):IMySet<T>;
    // 获取交集
    getIntersectionSet(newSet:IMySet<T>):IMySet<T>;
    // 获取差集
    getDifferenceSet(newSet:IMySet<T>):IMySet<T>;
    // 判断是否是子集
    isSubset(parSet:IMySet<T>):boolean;
}

下面实现 MySet 类:

class MySet<T> implements IMySet<T>{
    private dataStore:{
        [propName:string]:T
    } = {};
    private _size:number = 0;
    add(ele:T):void{
        // 判断该元素是否存在
        if(!this.has(ele)){
            // 获取字符串的键值
            const key:string = ele.toString();
            this.dataStore[key] = ele;
            this._size++;
        }
    }
    remove(ele:T):T{
        // 获取字符串的键值
        const key:string = ele.toString();
        // 获取元素
        const val:T = this.dataStore[key];
        // 删除 dataStore 上的键
        delete this.dataStore[key]
        this._size--;
        return val;
    }
    has(ele:T):boolean{
        const key:string = ele.toString();
        // 通过 hasOwnProperty 方法判断集合中是否存在某个值
        return this.dataStore.hasOwnProperty(key);
    }
    size():number{
        return this._size;
    }
    clear():void{
        // 情况集合
        this.dataStore = {};
    }
    toString():T[]{
        // 遍历 dataStore 中的所有键值
        const res:T[] = Object.keys(this.dataStore).map(v => this.dataStore[v]);
        return res;
    }
    // 获取并集
    getUnionSet(newSet:IMySet<T>):IMySet<T>{
        const 
            // 新建空集合
            tmp:IMySet<T> = new MySet<T>(),
            // 获取新集合中的所有值
            newSetVals:T[] = newSet.toString(),
            // 获取当前集合中的所有值
            currentSetVals:T[] = this.toString();
        // 遍历新集合
        newSetVals.forEach(v => {
            tmp.add(v);
        })

        // 遍历当前集合
        currentSetVals.forEach(v => {
            tmp.add(v);
        })

        return tmp;
    }
    // 获取交集
    getIntersectionSet(newSet:IMySet<T>):IMySet<T>{
        const 
            // 新建空集合
            tmp:IMySet<T> = new MySet<T>(),
            // 获取新集合中的所有值
            newSetVals:T[] = newSet.toString();

        newSetVals.forEach(v => {
            if(this.has(v)){
                tmp.add(v);
            }
        })
        return tmp;
    }
    // 获取差集
    getDifferenceSet(newSet:IMySet<T>):IMySet<T>{
        const 
            // 新建空集合
            tmp:IMySet<T> = new MySet<T>(),
            // 获取新集合中的所有值
            newSetVals:T[] = newSet.toString();

        newSetVals.forEach(v => {
            if(!this.has(v)){
                tmp.add(v);
            }
        })
        return tmp;
    }
    // 判断是否是子集
    isSubset(parSet:IMySet<T>):boolean{
        const 
            // 获取父集合的所有元素
            parSetVals:T[] = parSet.toString(),
            // 获取当前集合的所有元素
            currentSetVals:T[] = this.toString();
        
        let res:boolean = false;
        if(parSet.size() >= this.size()){
            // 判断当前集合中的元素是否都存在于父集合中
            res = currentSetVals.every(v => parSet.has(v))
        }
        return res;
    }
}

集合实现原理浅析

在 ES6 的 Set 出现以前,主要借助 JavaScript 中的对象实现。集合的实现原理:当向集合中添加元素时(调用 add() 方法),在对象中创建一个和新增元素对应的键,值就是新增的元素。
使用对象模拟的集合大概是这样:

{
  "A":"A",
  "B":"B",
  "C":"C",
  ...
}

由于 JavaScript 对象的限制只能使用字符串或者数字作为键,在向集合中添加复杂的数据结构时,需要将这些数据结构转换为字符串添加到对象中。因此下面的代码,只有第一个 add() 方法调用生效:

const set = new MySet<{name:string}>();
set.add({name:"MIKE"})
set.add({name:"JERRY"})
set.add({name:"PENNY"})

上面的调用结果中,集合中只有一个元素:{name:"MIKE"},且集合的键为:[object Object]
为了解决这个问题,可以在添加元素时使用差异化的键,这就要求对不同的元素求一个独特的特征值,这有点像散列的做法,当然这是我个人的想法,对于集合肯定还有其他的实现,如果您有其他的方案,可以在评论区留言。

完。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,544评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,430评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,764评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,193评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,216评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,182评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,063评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,917评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,329评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,543评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,722评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,425评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,019评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,671评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,825评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,729评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,614评论 2 353

推荐阅读更多精彩内容