ARTS打卡计划第5周

Wesley13
• 阅读 604

   在项目开发过程中,我们经常会遇到树形数据结构的设计,例如菜单树,地区树和类别树等等。一般而言,我们需要把数据库中记录全取出来,然后构建树(注意的是,最好是一次性取出来,如果是ajax按需拉数据则不需要)。下面分享了递归和非递归两种方式:

package test.tree;

import java.util.ArrayList;
import java.util.List;

public class Node {

    private String id;
    private String parentId;

    private String value;
    private Node parent;

    private List<Node> children;

    public Node() {
        super();
        this.children = new ArrayList<>();
    }

    public Node(String value, String id, String parentId) {
        this.value = value;
        this.id = id;
        this.parentId = parentId;
        this.children = new ArrayList<>();
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getParentId() {
        return parentId;
    }

    public void setParentId(String parentId) {
        this.parentId = parentId;
    }

    public Node getParent() {
        return parent;
    }

    public void setParent(Node parent) {
        this.parent = parent;
    }

    public List<Node> getChildren() {
        return children;
    }

    public void setChildren(List<Node> children) {
        this.children = children;
    }

    public void addChild(Node child) {
        if (!this.children.contains(child) && child != null)
            this.children.add(child);
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj instanceof Node) {
            if(this.id.equals(((Node) obj).getId())) {
                return true;
            }
        }
        return false;
    }
    @Override
    public String toString() {
        return "Node [id=" + id + ", parentId=" + parentId + ", value=" + value + ", children=" + children + "]";
    }
}

  非递归的方式

package test.tree;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ListToTreeNoRecurse {

    public static void main(String[] args) throws IOException {
        List<Node> nodes = new ArrayList<>();
        List<String> lines = Files
                .readAllLines(Paths.get("C:\\Users\\95\\Desktop\\leetCode\\src\\test\\tree\\jsontest.txt"));
        nodes.add(new Node("all", "0", null));
        for (String line : lines) {
            String[] values = line.split(",");
            Node node = new Node(values[1].trim(), values[0].trim(), values[3].trim());
            nodes.add(node);
        }

        long start = System.currentTimeMillis();
        createTree(nodes);
        long end = System.currentTimeMillis();
        System.err.println((end - start));

    }

    private static void createTree(List<Node> nodes) {

        Map<String, Node> mapTmp = new HashMap<>();
        // Save all nodes to a map
        for (Node current : nodes) {    
            mapTmp.put(current.getId(), current);
        
        }
        // loop and assign parent/child relationships
        for (Node current : nodes) {
            String parentId = current.getParentId();
            if (parentId != null) {
                Node parent = mapTmp.get(parentId);
                if (parent != null) {
                    current.setParent(parent);
                    parent.addChild(current);
                    mapTmp.put(parentId, parent);
                    mapTmp.put(current.getId(), current);
                }
            }

        }

        System.out.println(mapTmp.get("0"));
        
    }
}

  递归的方法来

package test.tree;
 
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import test.tree.Node;
 

public class TreeBuilder {
 
 
    /**
     * 使用递归方法建树
     * @param Nodes
     * @return
     */
    public static List<Node> buildByRecursive(List<Node> Nodes) {
        List<Node> trees = new ArrayList<Node>();
        for (Node Node : Nodes) {
            if ("0".equals(Node.getParentId())) {
                trees.add(findChildren(Node,Nodes));
            }
        }
        return trees;
    }
 
    /**
     * 递归查找子节点
     * @param Nodes
     * @return
     */
    public static Node findChildren(Node Node,List<Node> Nodes) {
        for (Node it : Nodes) {
            if(Node.getId().equals(it.getParentId())) {
                if (Node.getChildren() == null) {
                    Node.setChildren(new ArrayList<Node>());
                }
                Node.getChildren().add(findChildren(it,Nodes));
            }
        }
        return Node;
    }
 
 
 
    public static void main(String[] args) throws IOException {
         List<Node> list = new ArrayList<Node>();
         List<String> lines =  Files.readAllLines(Paths.get("C:\\Users\\95\\Desktop\\leetCode\\src\\test\\tree\\jsontest.txt"));
        for(String line:lines) {
            String[] values = line.split(",");
            Node node = new Node(values[1], values[0], values[3]);        
            list.add(node);
        }
        
        long beforeUsedMem=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
        long start = System.currentTimeMillis();
        List<Node> trees_ = TreeBuilder.buildByRecursive(list);
        long afterUsedMem=Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory();
        
        long actualMemUsed=afterUsedMem-beforeUsedMem;

        long end = System.currentTimeMillis();
        System.out.println(trees_);
        System.err.println((end - start));
        System.err.println(actualMemUsed);
    }
 
}

  上述方法的测试数据是世界地区数据,下载地址是:https://epubi.oss-cn-shanghai.aliyuncs.com/jsontest.txt

  经过测试,如果不打印树的话,非递归方法构建树是非常快的,远少于递归方法。打印树的话,非递归的方法的性能是略微优于递归的。

  因为非递归方法构建的时候,只是构建child,parent之间的引用,在真正打印的时候,会调用toString方法对child进行打印,这个时候也是一个遍历的过程。在项目中还是推荐使用非递归方法,非递归方法比较可控。

  该方法继承至AbstractCollection中的toString方法。

public String toString() {
        Iterator<E> it = iterator();
        if (! it.hasNext())
            return "[]";

        StringBuilder sb = new StringBuilder();
        sb.append('[');
        for (;;) {
            E e = it.next();
            sb.append(e == this ? "(this Collection)" : e);
            if (! it.hasNext())
                return sb.append(']').toString();
            sb.append(',').append(' ');
        }
    }
点赞
收藏
评论区
推荐文章
xxkfz xxkfz
2年前
使用Stream流递归实现遍历树形结构
可能平常会遇到一些需求,比如构建菜单,构建树形结构,数据库一般就使用父id来表示,为了降低数据库的查询压力,我们可以使用Java8中的Stream流一次性把数据查出来,然后通过流式处理,我们一起来看看,代码实现为了实现简单,就模拟查看数据库所有数据到List里面。比如现在有一张菜单表,具体数据如下:下面我们就来模拟这一操作,递归组装树形结构:@Autowi
待兔 待兔
2个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
秃头王路飞 秃头王路飞
2年前
浏览器工作原理
浏览器渲染过程浏览器渲染1.解析HTML文件,构建DOM树,同时浏览器主进程负责下载CSS文件2.CSS文件下载完成,解析CSS文件成树形的数据结构,然后结合DOM树合并成RenderObject树3.布局RenderObject树(Layout/reflow),负责RenderObject树中的元素的尺寸,位置等计算4.绘制RenderObject树(paint),绘制页面的像素信息5.浏览器主进程将默认的图层和复合图层交给GPU进程,GPU进
22 22
3年前
二叉树创建后,如何使用递归和栈遍历二叉树?
0.前言前文主要介绍了树的相关概念和原理,本文主要内容为二叉树的创建及遍历的代码实现,其中包括递归遍历和栈遍历。1.二叉树的实现思路1.0.顺序存储——数组实现前面介绍了满二叉树和完全二叉树,我们对其进行了编号——从0到n的不中断顺序编号,而恰好,数组也有一个这样的编号——数组下标,只要我们把二者联合起来,数组就能存储二叉树了。那么非满
Wesley13 Wesley13
2年前
JAVA递归实现线索化二叉树
JAVA递归实现线索化二叉树基础理论首先,二叉树递归遍历分为先序遍历、中序遍历和后序遍历。先序遍历为:根节点左子树右子树中序遍历为:左子树根节点右子树后序遍历为:左子树右子树根节点(只要记住根节点在哪里就是什么遍历,且都是先左再右)线索化现在有这么一棵二叉树,它的数据结
Stella981 Stella981
2年前
Data Structures 之 树
链表的访问速度太慢,不适合大量的输入数据。而树的大部分运行时间平均为O(logN)。定义树的一种自然的额方式是递归的方法。1.实现二叉树TianryTree.htypedefintElementType;ifndefBINARYTREE_H_INCLUDEDdefine
Wesley13 Wesley13
2年前
MySQL面试(二)
1、为什么索引遵循最左匹配原则?  当B树的数据项是符合的数据结构,比如(name,age,sex)的时候,B树是按照从左到右的顺序建立搜索树的。比如当(张三,20,F)这样的数据来检索的时候,b树会优先比较name来确定下一步的所搜方向,如果name相同再依次比较age和sex,最后得到检索的数据;但当(20,F)这样的没有name的数据来的时候
Wesley13 Wesley13
2年前
MySQL知识体系——索引
    本文直切主题,针对InnoDB引擎描述索引及优化策略。在开始之前,需要读者了解:1)二叉查找树(包括23查找树、红黑树等数据结构)2)MySQL的InnoDB引擎基础知识索引初探要了解索引,当然要了解其数据结构。树有很多应用,流行的用法之一是包括UNIX和DOS在内的许多常用操作系统中的目录结构,二叉查找树又是Java中两种集合
Wesley13 Wesley13
2年前
Java数据结构和算法(十五)——无权无向图
前面我们介绍了树这种数据结构,树是由n(n0)个有限节点通过连接它们的边组成一个具有层次关系的集合,把它叫做“树”是因为它看起来像一棵倒挂的树,包括二叉树、红黑树、234树、堆等各种不同的树,有对这几种树不了解的可以参考我前面几篇博客。而本篇博客我们将介绍另外一种数据结构——图,图也是计算机程序设计中最常用的数据结构之一,从数学意义上讲
Wesley13 Wesley13
2年前
B
BTreeBTree又叫做B树,和平衡二叉树不同的地方在于B树是多叉树(平衡多路查找树),Oracle和MongoDB的索引技术就是基于B树的数据结构,B树也可以看作是对23查找树的一种扩展。一个m阶的BTree有以下性质1.每个节点最多有m个子节点;2.每个非叶子节点(根节点除外)至少含有m/2个子节点;3.