js构建二叉树进行数值数组的去重与优化详解


Posted in Javascript onMarch 26, 2018

前言

本文主要介绍了关于js构建二叉树进行数值数组的去重与优化的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

常见两层循环实现数组去重

let arr = [11, 12, 13, 9, 8, 7, 0, 1, 2, 2, 5, 7, 11, 11, 7, 6, 4, 5, 2, 2]
let newArr = []
for (let i = 0; i < arr.length; i++) {
 let unique = true
 for (let j = 0; j < newArr.length; j++) {
  if (newArr[j] === arr[i]) {
   unique = false
   break
  }
 }
 if (unique) {
  newArr.push(arr[i])
 }
}
console.log(newArr)

构建二叉树实现去重(仅适用于数值类型的数组)

将先前遍历过的元素,构建成二叉树,树中每个结点都满足:左子结点的值 < 当前结点的值 < 右子结点的值

这样优化了判断元素是否之前出现过的过程

若元素比当前结点大,只需要判断元素是否在结点的右子树中出现过即可

若元素比当前结点小,只需要判断元素是否在结点的左子树中出现过即可

let arr = [0, 1, 2, 2, 5, 7, 11, 7, 6, 4,5, 2, 2]
class Node {
 constructor(value) {
  this.value = value
  this.left = null
  this.right = null
 }
}
class BinaryTree {
 constructor() {
  this.root = null
  this.arr = []
 }

 insert(value) {
  let node = new Node(value)
  if (!this.root) {
   this.root = node
   this.arr.push(value)
   return this.arr
  }
  let current = this.root
  while (true) {
   if (value > current.value) {
    if (current.right) {
     current = current.right
    } else {
     current.right = node
     this.arr.push(value)
     break
    }
   }
   if (value < current.value) {
    if (current.left) {
     current = current.left
    } else {
     current.left = node
     this.arr.push(value)
     break
    }
   }
   if (value === current.value) {
    break
   }
  }
  return this.arr
 }
}

let binaryTree = new BinaryTree()
for (let i = 0; i < arr.length; i++) {
 binaryTree.insert(arr[i])
}
console.log(binaryTree.arr)

优化思路一,记录最大最小值

记录已经插入元素的最大最小值,若比最大元素大,或最小元素小,则直接插入

let arr = [11, 12, 13, 9, 8, 7, 0, 1, 2, 2, 5, 7, 11, 11, 7, 6, 4, 5, 2, 2]
class Node {
 constructor(value) {
  this.value = value
  this.left = null
  this.right = null
 }
}
class BinaryTree {
 constructor() {
  this.root = null
  this.arr = []
  this.max = null
  this.min = null
 }

 insert(value) {
  let node = new Node(value)
  if (!this.root) {
   this.root = node
   this.arr.push(value)
   this.max = value
   this.min = value
   return this.arr
  }
  if (value > this.max) {
   this.arr.push(value)
   this.max = value
   this.findMax().right = node
   return this.arr
  }
  if (value < this.min) {
   this.arr.push(value)
   this.min = value
   this.findMin().left = node
   return this.arr
  }
  let current = this.root
  while (true) {
   if (value > current.value) {
    if (current.right) {
     current = current.right
    } else {
     current.right = node
     this.arr.push(value)
     break
    }
   }
   if (value < current.value) {
    if (current.left) {
     current = current.left
    } else {
     current.left = node
     this.arr.push(value)
     break
    }
   }
   if (value === current.value) {
    break
   }
  }
  return this.arr
 }

 findMax() {
  let current = this.root
  while (current.right) {
   current = current.right
  }
  return current
 }

 findMin() {
  let current = this.root
  while (current.left) {
   current = current.left
  }
  return current
 }
}

let binaryTree = new BinaryTree()
for (let i = 0; i < arr.length; i++) {
 binaryTree.insert(arr[i])
}
console.log(binaryTree.arr)

优化思路二,构建红黑树

构建红黑树,平衡树的高度

有关红黑树的部分,请见红黑树的插入

let arr = [11, 12, 13, 9, 8, 7, 0, 1, 2, 2, 5, 7, 11, 11, 7, 6, 4, 5, 2, 2]
console.log(Array.from(new Set(arr)))

class Node {
 constructor(value) {
  this.value = value
  this.left = null
  this.right = null
  this.parent = null
  this.color = 'red'
 }
}

class RedBlackTree {
 constructor() {
  this.root = null
  this.arr = []
 }

 insert(value) {
  let node = new Node(value)
  if (!this.root) {
   node.color = 'black'
   this.root = node
   this.arr.push(value)
   return this
  }
  let cur = this.root
  let inserted = false
  while (true) {
   if (value > cur.value) {
    if (cur.right) {
     cur = cur.right
    } else {
     cur.right = node
     this.arr.push(value)
     node.parent = cur
     inserted = true
     break
    }
   }

   if (value < cur.value) {
    if (cur.left) {
     cur = cur.left
    } else {
     cur.left = node
     this.arr.push(value)
     node.parent = cur
     inserted = true
     break
    }
   }

   if (value === cur.value) {
    break
   }
  }
  // 调整树的结构
  if(inserted){
   this.fixTree(node)
  }
  return this
 }

 fixTree(node) {
  if (!node.parent) {
   node.color = 'black'
   this.root = node
   return
  }
  if (node.parent.color === 'black') {
   return
  }
  let son = node
  let father = node.parent
  let grandFather = father.parent
  let directionFtoG = father === grandFather.left ? 'left' : 'right'
  let uncle = grandFather[directionFtoG === 'left' ? 'right' : 'left']
  let directionStoF = son === father.left ? 'left' : 'right'
  if (!uncle || uncle.color === 'black') {
   if (directionFtoG === directionStoF) {
    if (grandFather.parent) {
     grandFather.parent[grandFather.parent.left === grandFather ? 'left' : 'right'] = father
     father.parent = grandFather.parent
    } else {
     this.root = father
     father.parent = null
    }
    father.color = 'black'
    grandFather.color = 'red'

    father[father.left === son ? 'right' : 'left'] && (father[father.left === son ? 'right' : 'left'].parent = grandFather)
    grandFather[grandFather.left === father ? 'left' : 'right'] = father[father.left === son ? 'right' : 'left']

    father[father.left === son ? 'right' : 'left'] = grandFather
    grandFather.parent = father
    return
   } else {
    grandFather[directionFtoG] = son
    son.parent = grandFather

    son[directionFtoG] && (son[directionFtoG].parent = father)
    father[directionStoF] = son[directionFtoG]

    father.parent = son
    son[directionFtoG] = father
    this.fixTree(father)
   }
  } else {
   father.color = 'black'
   uncle.color = 'black'
   grandFather.color = 'red'
   this.fixTree(grandFather)
  }
 }
}

let redBlackTree = new RedBlackTree()
for (let i = 0; i < arr.length; i++) {
 redBlackTree.insert(arr[i])
}
console.log(redBlackTree.arr)

其他去重方法

通过 Set 对象去重

[...new Set(arr)]

通过 sort() + reduce() 方法去重

排序后比较相邻元素是否相同,若不同则添加至返回的数组中

值得注意的是,排序的时候,默认 compare(2, '2') 返回 0;而 reduce() 时,进行全等比较

let arr = [0, 1, 2, '2', 2, 5, 7, 11, 7, 5, 2, '2', 2]
let newArr = []
arr.sort((a, b) => {
 let res = a - b
 if (res !== 0) {
  return res
 } else {
  if (a === b) {
   return 0
  } else {
   if (typeof a === 'number') {
    return -1
   } else {
    return 1
   }
  }
 }
}).reduce((pre, cur) => {
 if (pre !== cur) {
  newArr.push(cur)
  return cur
 }
 return pre
}, null)

通过 includes() + map() 方法去重

let arr = [0, 1, 2, '2', 2, 5, 7, 11, 7, 5, 2, '2', 2]
let newArr = []
arr.map(a => !newArr.includes(a) && newArr.push(a))

通过 includes() + reduce() 方法去重

let arr = [0, 1, 2, '2', 2, 5, 7, 11, 7, 5, 2, '2', 2]
let newArr = arr.reduce((pre, cur) => {
  !pre.includes(cur) && pre.push(cur)
  return pre
}, [])

通过对象的键值对 + JSON 对象方法去重

let arr = [0, 1, 2, '2', 2, 5, 7, 11, 7, 5, 2, '2', 2]
let obj = {}
arr.map(a => {
  if(!obj[JSON.stringify(a)]){
    obj[JSON.stringify(a)] = 1
  }
})
console.log(Object.keys(obj).map(a => JSON.parse(a)))

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
js日期时间补零的小例子
Mar 05 Javascript
jquery上传插件fineuploader上传文件使用方法(jquery图片上传插件)
Dec 05 Javascript
js获得页面的高度和宽度的方法
Feb 23 Javascript
php析构函数的具体用法小结
Mar 11 Javascript
浅谈angularJS 作用域
Jul 05 Javascript
JS+CSS实现的竖向简洁折叠菜单效果代码
Oct 22 Javascript
node.js抓取并分析网页内容有无特殊内容的js文件
Nov 17 Javascript
jQuery实现下拉框左右移动(全部移动,已选移动)
Apr 15 Javascript
jQuery layui常用方法介绍
Jul 25 Javascript
8 行 Node.js 代码实现代理服务器
Dec 05 Javascript
详解vuex状态管理模式
Nov 01 Javascript
js实现验证码干扰(静态)
Feb 22 Javascript
红黑树的插入详解及Javascript实现方法示例
Mar 26 #Javascript
js+canvas实现滑动拼图验证码功能
Mar 26 #Javascript
JS从非数组对象转数组的方法小结
Mar 26 #Javascript
深入理解Node module模块
Mar 26 #Javascript
利用Console来Debug的10个高级技巧汇总
Mar 26 #Javascript
关于vuejs中v-if和v-show的区别及v-show不起作用问题
Mar 26 #Javascript
vue中使用iview自定义验证关键词输入框问题及解决方法
Mar 26 #Javascript
You might like
smarty内置函数section的用法
2015/01/22 PHP
PHP 实现 WebSocket 协议原理与应用详解
2020/04/22 PHP
JS、jquery实现几分钟前、几小时前、几天前等时间差显示效果的代码实例分享
2014/04/11 Javascript
jQuery照片伸缩效果不影响其他元素的布局
2014/05/09 Javascript
浅谈JavaScript事件的属性列表
2015/03/01 Javascript
JS正则表达式判断有效数实例代码
2017/03/13 Javascript
vue引入新版 vue-awesome-swiper插件填坑问题
2018/01/25 Javascript
vue移动端微信授权登录插件封装的实例
2018/08/28 Javascript
vue-router源码之history类的浅析
2019/05/21 Javascript
vue3.0中的双向数据绑定方法及优缺点
2019/08/01 Javascript
关于layui的动态图标不显示的解决方法
2019/09/04 Javascript
vue.js 子组件无法获取父组件store值的解决方式
2019/11/08 Javascript
如何使用 vue-cli 创建模板项目
2020/11/19 Vue.js
[33:09]完美世界DOTA2联赛循环赛 Forest vs DM BO2第二场 10.29
2020/10/29 DOTA
举例讲解Python面向对象编程中类的继承
2016/06/17 Python
使用Numpy读取CSV文件,并进行行列删除的操作方法
2018/07/04 Python
使用Python在Windows下获取USB PID&amp;VID的方法
2019/07/02 Python
python的debug实用工具 pdb详解
2019/07/12 Python
Django 对象关系映射(ORM)源码详解
2019/08/06 Python
使用python的turtle绘画滑稽脸实例
2019/11/21 Python
一文弄懂Pytorch的DataLoader, DataSet, Sampler之间的关系
2020/07/03 Python
从零实现一个自定义html5播放器的示例代码
2017/08/01 HTML / CSS
JDK安装目录下有哪些内容
2014/08/25 面试题
什么是Linux虚拟文件系统VFS
2015/08/25 面试题
预防煤气中毒方案
2014/06/16 职场文书
网络文明传播志愿者活动方案
2014/08/20 职场文书
职工小家建设活动方案
2014/08/25 职场文书
2015个人半年总结范文
2015/03/09 职场文书
简历自我评价优缺点
2015/03/11 职场文书
2015年幼儿园教研活动总结
2015/03/25 职场文书
2015年感恩母亲节活动方案
2015/05/04 职场文书
TypeScript中条件类型精读与实践记录
2021/10/05 Javascript
SQL语法CONSTRAINT约束操作详情
2022/01/18 MySQL
Sql Server之数据类型详解
2022/02/28 SQL Server
python和anaconda的区别
2022/05/06 Python
前端框架ECharts dataset对数据可视化的高级管理
2022/12/24 Javascript