树是一种非散列数据结构,和非散列表一样,它对于存储需要快速查找的数据非常有用。

树是一种分层数据的抽象模型。现实生活中最常见的树的例子是家谱,或是公司的组织架构

本文将讲述一个实例,构造一棵树来实现数组和tree的相互转换,这在前端树结构中是经常遇到的。

需求场景:

将数组转化树结构,并将树结构转化为数组

数组

const list= [{ id: 1001, parentId: 0, name: 'AA' },{ id: 1002, parentId: 1001, name: 'BB' },{ id: 1009, parentId: 1005, name: 'II' },{ id: 1003, parentId: 1001, name: 'CC' },{ id: 1004, parentId: 1003, name: 'DD' },{ id: 1005, parentId: 1003, name: 'EE' },{ id: 1006, parentId: 1002, name: 'FF' },{ id: 1007, parentId: 1002, name: 'GG' },{ id: 1008, parentId: 1004, name: 'HH' },];

分析:

数组list是无规则排序的,不过分析过后,可以看到是一个通过parentId关联的树,那么如何实现呢?

树结构是一个对象,有一个root节点,并且有一系列的方法,比如插入节点,删除节点,获取节点,获取深度等等。

节点也是一个对象,有一定的属性,而且节点的属性也可能是其他的树。

那么我们可以先构造一个节点对象Node,每个Node有id, parentId, name, childNodes属性

构造一棵树listTree,先在数组中找到根节点(parentId === 0)

再给listTree添加list数组中的元素,直到添加完毕,就得到了树结构

实现步骤:

1,构造Node

class Node {constructor(options){let { id, parentId, name } = optionsthis.id = id || null;this.parentId = parentId;this.name = name || null;this.childNodes = []}getId(){return this.id;}...
}

2,构造树listTree

创建listTree时,初始化this.root,生成this.root(generateRoot)

由于在root上添加节点,所以增加了insertNode方法,插入时要找到root中对用的parentId

代码如下:

class listTree{constructor(arr){this.root = new Node(arr.find(item => item.parentId === 0))this.generateRoot(arr)}generateRoot(arr){// ...}getNodeById(id){// ...}insertNode(node, id){let targetNode = this.getNodeById(id)// ...}// ...
}

3,完善listTree

getNodeById(id):遍历this.root,找到对应元素,这里采取横向遍历,减少计算量

insertNode实现:根据要插入节点的parentId,找到父节点,然后把要插入的节点加入到父节点数组中

generateRoot:每次向listTree树加入节点后,在目标数组中删除该元素,直到目标数组为空

代码如下:

class listTree{constructor(arr){this.root = new Node(arr.find(item => item.parentId === 0))this.generateRoot(arr)}generateRoot(arr){let arrRest = arr;let self = this;let rootIndex = arr.findIndex(item => item.parentId === 0)arrRest.splice(rootIndex,1)reduceArrRest()function reduceArrRest(){arrRest.forEach((node,index) => {let result = self.insertNode(new Node(node),node.parentId)if(result){arrRest.splice(index,1)}})// 有剩余的元素没有插入到树结构, 继续循环插入if(arrRest.length > 0){reduceArrRest()}}}getNodeById(id){if(this.root && this.root.id === id){return this.root}let targetNode = null;compareNodeId(id,this.root.childNodes)return targetNode;function compareNodeId(id, NodeList){// 在遍历下一个节点时,先判断是否已经找到targetNodeif(targetNode){return targetNode}// 先遍历NodeList数组(采取的广度遍历)for ( let node of NodeList){if(node.id === id){targetNode = nodebreak}}// NodeList数组中没找到,再到NodeList每个node的child中查找if(!targetNode){for ( let node of NodeList){if(node.childNodes.length>0){compareNodeId(id,node.childNodes)}}}return targetNode}}insertNode(node, id){let targetNode = this.getNodeById(id)if(targetNode){targetNode.childNodes.push(node)return true} else {return false}}
}

4, 实现树结构转化为数组

递归遍历树结构

class listTree{constructor(arr){this.root = new Node(arr.find(item => item.parentId === 0))}// ...toArray(){let list = [];pushNode(this.root)function pushNode(node){let { id, parentId, name } = node;list.push({id, parentId, name})if(node.childNodes.length>0){for ( let nodeItem of node.childNodes){pushNode(nodeItem) }}}return list}
}

以上就实现了基本的功能

demo

function listToTree(arr){let ListTree = new listTree(arr)console.log(JSON.stringify(ListTree.root,null, 2))console.log(JSON.stringify(ListTree.toArray(),null,2))
}listToTree(list)

运行结果:

树结构:

{"id": 1001,"parentId": 0,"name": "AA","childNodes": [{"id": 1002,"parentId": 1001,"name": "BB","childNodes": [{"id": 1007,"parentId": 1002,"name": "GG","childNodes": []},{"id": 1006,"parentId": 1002,"name": "FF","childNodes": []}]},{"id": 1003,"parentId": 1001,"name": "CC","childNodes": [{"id": 1005,"parentId": 1003,"name": "EE","childNodes": [{"id": 1009,"parentId": 1005,"name": "II","childNodes": []}]},{"id": 1004,"parentId": 1003,"name": "DD","childNodes": [{"id": 1008,"parentId": 1004,"name": "HH","childNodes": []}]}]}]
}

数组:

[{"id": 1001,"parentId": 0,"name": "AA"},{"id": 1002,"parentId": 1001,"name": "BB"},{"id": 1007,"parentId": 1002,"name": "GG"},{"id": 1006,"parentId": 1002,"name": "FF"},{"id": 1003,"parentId": 1001,"name": "CC"},{"id": 1005,"parentId": 1003,"name": "EE"},{"id": 1009,"parentId": 1005,"name": "II"},{"id": 1004,"parentId": 1003,"name": "DD"},{"id": 1008,"parentId": 1004,"name": "HH"}
]

总结:树结构的形式有很多,不过还是会归结到树节点,树方法上。

树结构使用实例---实现数组和树结构的转换相关推荐

  1. 扁平数组转树结构C++实现方式

    背景 今天遇到一个题,需要将扁平数组转树结构,题目大致如下 将扁平数组转为树结构输出 pid0为根节点,id顺序可能不递增,pid可能不存在于数组内 给定输入 [{id: 1, name: '111' ...

  2. Java-Runoob-高级教程-实例-数组:10. Java 实例 – 查找数组中的重复元素-un

    ylbtech-Java-Runoob-高级教程-实例-数组:10. Java 实例 – 查找数组中的重复元素 1.返回顶部 1. Java 实例 - 查找数组中的重复元素  Java 实例 以下实例 ...

  3. Java中9大内置基本数据类型Class实例和数组的Class实例

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 1.Java中9大内置几本数据类型: 对于对象来说,可以直接使用对象.getClass()或者Cla ...

  4. 一维数组元素倒置 c语言,实例12 数组中元素的倒置.pdf

    第1 篇 C 语言基础知识 第1 章 走入C 语言的世界 实例12 数组中元素的倒置 [实例描述] 让一维数组中的元素转置,也就是让数组的元素本末倒置,即第 一个元素变成最后一个元素,第二个元素变成倒 ...

  5. python中 tolist_python 列表,数组,矩阵两两转换tolist()的实例

    通过代码熟悉过程: # -*- coding: utf-8 -*- from numpy import * a1 =[[1,2,3],[4,5,6]] #列表 print('a1 :',a1) #(' ...

  6. Java-Runoob-高级教程-实例-数组:03. Java 实例 – 获取数组长度-*

    ylbtech-Java-Runoob-高级教程-实例-数组:03. Java 实例 – 获取数组长度 1.返回顶部 Java 实例 - 获取数组长度  Java 实例 本文我们将为大家介绍如何使用数 ...

  7. php键值字符串转数组,PHP数组与字符串互相转换实例

    PHP 数组转字符串,与字符串转数组 $array = array('lastname', 'email', 'phone'); $comma_separated = implode(",& ...

  8. android 字符串数组去重,GitHub - deng-ming-hao/ec-do: 实例为日常开发常用的小实例,包括数组去重,打乱数组,字母大小写转换,cookie操作的封装等。...

    ec-do 自己封装的常用操作实例 实例为日常开发常用的小实例,包括数组去重,打乱数组,字母大小写转换,cookie操作的封装等. 使用方法 引入ec-do.js //去除空格 ecDo.trim(' ...

  9. java数组查找指定元素_Java 实例 - 在数组中查找指定元素

    以下实例演示了如何使用 contains () 方法来查找数组中的指定元素:/* author by w3cschool.cc 文件名:Main.java */import java.util.Arr ...

最新文章

  1. poj3624 Charm Bracelet DP 01背包问题
  2. java 反射加实例化内部类
  3. 辛苦了一个下午和晚上,给Blog换了个新皮肤
  4. 在 emu8086 中学习汇编In,Out指令
  5. 轻松了解“Web应用防火墙”
  6. 牛客多校4 - Harder Gcd Problem(构造+贪心)
  7. 计算机基础知识题库选择题,计算机基础知识篇选择题库
  8. 治疗拖延症晚期患者的三张处方
  9. iNeuOS工业互联网操作系统部署在华为欧拉(openEuler)国产系统
  10. 设计模式C++实现(3)——建造者模式
  11. linux和win10运行效率,Ubuntu与Win10周年版Ubuntu Bash性能对比
  12. 包头市民族中学2021高考成绩查询,2021庆阳高考成绩查询系统入口
  13. linux锐捷代码_锐捷认证 For Linux
  14. 软件测试之兼容性测试
  15. python 批量打印PDF(转)
  16. Dialogs(对话框)
  17. Oracle技巧之 desc+表名
  18. Shiro框架Given final block not properly padded问题解决
  19. 一个简单的推荐系统实现
  20. 【接口测试基础】第五篇 | 接口用例设计详解

热门文章

  1. 中国大学慕课 大连理工大学 C语言程序设计 第四周编程作业 选择结构程序设计
  2. 2023年全国最新道路运输从业人员精选真题及答案44
  3. 三星p601刷android9,三星P601线刷刷机教程_三星P601 rom包_救砖系统刷机包
  4. SDK和API 区别
  5. 如何查看process name全名
  6. 前端开发-HTML+CSS实现网易新闻网右侧新闻列表
  7. 生物信息学算法之Python实现|Rosalind刷题笔记:004 求DNA的反向互补序列
  8. 如何在spring中使用缓存
  9. Vue+Three.js建造3D小房子
  10. 编程n的阶乘使用while语句_数控宏程序编程----学习笔记