JavaScript数据结构与算法之集合(Set)


Posted in Javascript onJanuary 29, 2016

集合(Set)

说起集合,就想起刚进高中时,数学第一课讲的就是集合。因此在学习集合这种数据结构时,倍感亲切。
集合的基本性质有一条: 集合中元素是不重复的。因为这种性质,所以我们选用了对象来作为集合的容器,而非数组。
虽然数组也能做到所有不重复,但终究过于繁琐,不如集合。

集合的操作

集合的基本操作有交集、并集、差集等。这儿我们介绍JavaScipt集合中交集、并集、差集的实现。

JavaScipt中集合的实现

首先,创建一个构造函数。

/**
 * 集合的构造函数
 */
function Set方法 {
 /**
  * 集合元素的容器,以对象来表示
  * @type {Object}
  */
 var items = {};
}

集合需要有如下方法:

  1. has(value): 检测集合内是否有某个元素
  2. add(value): 给集合内添加某个元素
  3. remove(value): 移除集合中某个元素
  4. clear(value): 清空集合
  5. size(): 返回集合长度
  6. values(): 返回集合转换的数组
  7. union(otherSet): 返回两个集合的并集
  8. intersection(otherSet): 返回两个集合的交集
  9. difference(otherSet): 返回两个集合的差集
  10. subset(otherSet): 判断该集合是否为传入集合的子集

has方法:

说明:集合中元素是不重复的。所以在其它任何操作前,必须用has方法确认集合是否有某个元素。这儿使用了hasOwnProperty方法来检测。
实现:

/**
 * 检测集合内是否有某个元素
 * @param {Any} value  要检测的元素
 * @return {Boolean}    如果有,返回true
 */
this.has = function(value) {
 // hasOwnProperty的问题在于
 // 它是一个方法,所以可能会被覆写
 return items.hasOwnProperty(value)
};

add方法:

说明: 给集合内添加某个元素。
实现:

/**
 * 给集合内添加某个元素
 * @param {Any} value 要被添加的元素
 * @return {Boolean}    添加成功返回True。
 */
this.add = function(value) {
 //先检测元素是否存在。
 if (!this.has(value)) {
  items[value] = value;
  return true;
 }
 //如果元素已存在则返回false
 return false;
};

remove方法:

说明: 移除集合中某个元素
实现:

/**
 * 移除集合中某个元素
 * @param {Any} value 要移除的元素
 * @return {Boolean}    移除成功返回True。
 */
this.remove = function(value) {
 //先检测元素是否存在。
 if (this.has(value)) {
  delete items[value];
  return true;
 }
 //如果元素不存在,则删除失败返回false
 return false;
};

clear方法:
说明: 清空集合
实现:

/**
 * 清空集合
 */
this.clear = function() {
 this.items = {};
};

size方法

说明: 返回集合长度,这儿有两种方法。第一种方法使用了Object.keys这个Api,但只支持IE9及以上。第二种则适用于所有浏览器。
实现:

/**
 * 返回集合长度,只可用于IE9及以上
 * @return {Number} 集合长度
 */
this.size = function() {
 // Object.keys方法能将对象转化为数组
 // 只可用于IE9及以上,但很方便
 return Object.keys(items).length;
}

/**
 * 返回集合长度,可用于所有浏览器
 * @return {Number} 集合长度
 */
this.sizeLegacy = function() {
 var count = 0;
 for (var prop in items) {
  if (items.hasOwnProperty(prop)) {
   ++count;
  }
 }
 return count;
}

values方法

说明: 返回集合转换的数组,这儿也有两种方法。理由同上。使用了Object.keys,只能支持IE9及以上。
实现:

/**
 * 返回集合转换的数组,只可用于IE9及以上
 * @return {Array} 转换后的数组
 */
this.values = function() {
 return Object.keys(items);
};

/**
 * 返回集合转换的数组,可用于所有浏览器
 * @return {Array} 转换后的数组
 */
this.valuesLegacy = function() {
 var keys = [];
 for (var key in items) {
  keys.push(key)
 };
 return keys;
};

union方法

说明: 返回两个集合的并集
实现:

/**
 * 返回两个集合的并集
 * @param {Set} otherSet 要进行并集操作的集合
 * @return {Set}     两个集合的并集
 */
this.union = function(otherSet) {
 //初始化一个新集合,用于表示并集。
 var unionSet = new Set();
 //将当前集合转换为数组,并依次添加进unionSet
 var values = this.values();
 for (var i = 0; i < values.length; i++) {
  unionSet.add(values[i]);
 }

 //将其它集合转换为数组,依次添加进unionSet。
 //循环中的add方法保证了不会有重复元素的出现
 values = otherSet.values();
 for (var i = 0; i < values.length; i++) {
  unionSet.add(values[i]);
 }

 return unionSet;
};

intersection方法

说明: 返回两个集合的交集
实现:

/**
 * 返回两个集合的交集
 * @param {Set} otherSet 要进行交集操作的集合
 * @return {Set}     两个集合的交集
 */
this.intersection = function(otherSet) {
 //初始化一个新集合,用于表示交集。
 var interSectionSet = new Set();
 //将当前集合转换为数组
 var values = this.values();
 //遍历数组,如果另外一个集合也有该元素,则interSectionSet加入该元素。
 for (var i = 0; i < values.length; i++) {

  if (otherSet.has(values[i])) {
   interSectionSet.add(values[i])
  }
 }

 return interSectionSet;
};

difference方法

说明: 返回两个集合的差集
实现:

/**
 * 返回两个集合的差集
 * @param {Set} otherSet 要进行差集操作的集合
 * @return {Set}     两个集合的差集
 */
this.difference = function(otherSet) {
 //初始化一个新集合,用于表示差集。
 var differenceSet = new Set();
 //将当前集合转换为数组
 var values = this.values();
 //遍历数组,如果另外一个集合没有该元素,则differenceSet加入该元素。
 for (var i = 0; i < values.length; i++) {

  if (!otherSet.has(values[i])) {
   differenceSet.add(values[i])
  }
 }

 return differenceSet;
};

subset方法

说明: 判断该集合是否为传入集合的子集。这段代码在我自己写完后与书上一比对,觉得自己超级low。我写的要遍历数组三次,书上的只需要一次,算法复杂度远远低于我的。
实现:

/**
 * 判断该集合是否为传入集合的子集
 * @param {Set} otherSet 传入的集合
 * @return {Boolean}   是则返回True
 */
this.subset = function(otherSet) {
 // 第一个判定,如果该集合长度大于otherSet的长度
 // 则直接返回false
 if (this.size() > otherSet.size()) {
  return false;
 } else {
  // 将当前集合转换为数组
  var values = this.values();

  for (var i = 0; i < values.length; i++) {

   if (!otherSet.has(values[i])) {
    // 第二个判定。只要有一个元素不在otherSet中
    // 那么则可以直接判定不是子集,返回false
    return false;
   }
  }

  return true;
 }
};

ES6中的集合

ES6也提供了集合,但之前看ES6的集合操作一直迷迷糊糊的。实现一遍后再去看,感觉概念清晰了很多。
具体的我掌握的不是很好,还在学习中,就不写出来啦~推荐看阮一峰老师的《ECMAScript 6入门》中对ES6 Set的介绍。
《ECMAScript 6入门》? Set和Map数据结构

感想

到了这儿,已经掌握了一些基本的数据结构。剩下的都是难啃的骨头了(对我而言)。

字典的散列表、图、树、排序算法。算是四大金刚,所以近期关于数据结构与算法系列的文章,可能会更新的很慢。对我来说,也算是一个坎。希望这个寒假,能跨过这个坎。

Javascript 相关文章推荐
IE中jquery.form中ajax提交没反应解决方法分享
Sep 11 Javascript
js汉字转拼音实现代码
Feb 06 Javascript
js调用后台servlet方法实例
Jun 09 Javascript
用jquery写的一个万年历(自写)
Jan 20 Javascript
jQuery Validation PlugIn的使用方法详解
Dec 18 Javascript
js获取新浪天气接口的实现代码
Jun 06 Javascript
AngularJS+bootstrap实现动态选择商品功能示例
May 17 Javascript
原生javascript实现连连看游戏
Jan 03 Javascript
在vue中动态添加class类进行显示隐藏实例
Nov 09 Javascript
使用JS location实现搜索框历史记录功能
Dec 23 Javascript
jQuery实现视频展示效果
May 30 jQuery
利用js实现简易红绿灯
Oct 15 Javascript
AngularJS 使用 UI Router 实现表单向导
Jan 29 #Javascript
JavaScript数据结构与算法之链表
Jan 29 #Javascript
动态创建按钮的JavaScript代码
Jan 29 #Javascript
JavaScript数据结构与算法之栈与队列
Jan 29 #Javascript
javascript实现表单验证
Jan 29 #Javascript
jQuery实现横向带缓冲的水平运动效果(附demo源码下载)
Jan 29 #Javascript
JavaScript判断DIV内容是否为空的方法
Jan 29 #Javascript
You might like
discuz7 phpMysql操作类
2009/06/21 PHP
php上传图片到指定位置路径保存到数据库的具体实现
2013/12/30 PHP
php导出csv文件,可导出前导0实例代码
2016/11/16 PHP
javascript 另一种图片滚动切换效果思路
2012/04/20 Javascript
JS调用CS里的带参方法实例
2013/08/01 Javascript
如何在JavaScript中实现私有属性的写类方式(二)
2013/12/04 Javascript
ie9 提示'console' 未定义问题的解决方法
2014/03/20 Javascript
Javascript基于对象三大特性(封装性、继承性、多态性)
2016/01/04 Javascript
JQuery插件Marquee.js实现无缝滚动效果
2016/04/26 Javascript
实例详解JSON取值(key是中文或者数字)方式
2017/08/24 Javascript
vue2.0 可折叠列表 v-for循环展示的实例
2018/09/07 Javascript
JS学习笔记之原型链和利用原型实现继承详解
2019/05/29 Javascript
vue+django实现一对一聊天功能的实例代码
2019/07/17 Javascript
Vue表单控件数据绑定方法详解
2020/02/05 Javascript
[02:55]2018DOTA2国际邀请赛勇士令状不朽珍藏Ⅲ饰品一览
2018/08/01 DOTA
[01:07:13]TNC vs Pain 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/20 DOTA
python修改操作系统时间的方法
2015/05/18 Python
教你用Python脚本快速为iOS10生成图标和截屏
2016/09/22 Python
用python简单实现mysql数据同步到ElasticSearch的教程
2018/05/30 Python
python爬虫之自制英汉字典
2019/06/24 Python
Python+Selenium随机生成手机验证码并检查页面上是否弹出重复手机号码提示框
2020/09/21 Python
Nisbets爱尔兰:英国最大的厨房和餐饮设备供应商
2019/01/26 全球购物
美国滑板店:Tactics
2020/11/08 全球购物
使用C#编写创建一个线程的代码
2013/01/22 面试题
手机业务员岗位职责
2013/12/13 职场文书
商务英语求职自荐信范文
2013/12/24 职场文书
调解员先进事迹材料
2014/02/07 职场文书
安全生产实施方案
2014/02/23 职场文书
财务总监管理岗位职责
2014/03/08 职场文书
党员教师学习党的群众路线教育实践活动心得体会
2014/10/31 职场文书
2014年学校卫生工作总结
2014/11/20 职场文书
​(迎国庆)作文之我爱我的祖国
2019/09/19 职场文书
创业计划书之烤红薯
2019/09/26 职场文书
MySQL的安装与配置详细教程
2021/06/26 MySQL
Python Flask搭建yolov3目标检测系统详解流程
2021/11/07 Python
vue.js 使用原生js实现轮播图
2022/04/26 Vue.js