树的遍历 订阅
树的遍历是树的一种重要的运算。所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次。二叉树的3种最重要的遍历方式分别称为前序遍历、中序遍历和后序遍历。以这3种方式遍历一棵树时,若按访问结点的先后次序将结点排列起来,就可分别得到树中所有结点的前序列表,中序列表和后序列表。相应的结点次序分别称为结点的前序、中序和后序。 展开全文
树的遍历是树的一种重要的运算。所谓遍历是指对树中所有结点的信息的访问,即依次对树中每个结点访问一次且仅访问一次。二叉树的3种最重要的遍历方式分别称为前序遍历、中序遍历和后序遍历。以这3种方式遍历一棵树时,若按访问结点的先后次序将结点排列起来,就可分别得到树中所有结点的前序列表,中序列表和后序列表。相应的结点次序分别称为结点的前序、中序和后序。
信息
类    别
计算机语言
分    类
前序,中序、后序
中文名
树的遍历
概    括
计算机的一种重要的运算
树的遍历定义
树的这3种遍历方式可递归地定义如下:如果T是一棵空树,那么对T进行前序遍历、中序遍历和后序遍历都是空操作,得到的列表为空表。如果T是一棵单结点树,那么对T进行前序遍历、中序遍历和后序遍历都只访问这个结点。这个结点本身就是要得到的相应列表。否则,设T如图6所示,它以n为树根,树根的子树从左到右依次为T1,T2,..,Tk,那么有:对T进行前序遍历是先访问树根n,然后依次前序遍历T1,T2,..,Tk。对T进行中序遍历是先中序遍历T1,然后访问树根n,接着依次对T2,T3,..,Tk进行中序遍历。对T进行后序遍历是先依次对T1,T2,..,Tk进行后序遍历,最后访问树根n。 前序遍历和中序遍历可形式地依次描述如下 :三种遍历可以形式地描述如下,其中用到了树的ADT操作:Procedure Preorder_Traversal(v:NodeType); {前序遍历算法}beginVisite(v); {访问节点v}i:=Leftmost_Child(v);while i<>∧ dobeginPreorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}i:=Right_Sibling(i);end;end;Procedure Inorder_Traversal(v:NodeType); {中序遍历算法}beginif Leftmost_Child(v)=∧ {判断v是否是叶节点}then Visite(v)elsebeginInorder_Traversal(Leftmost_Child(v)); {中序遍历v的左边第一个儿子节点}Visite(v); {访问节点v}i:=Right_Sibling(Leftmost_Child(v)); {i=v的左边第二个儿子}while i<>∧ dobeginInorder_Traversal(i);{从左边第二个开始到最右边一个为止依次访问v的每一个儿子节点i}i:=Right_Sibling(i);end;end;end;Procedure Postorder_Traversal(v:NodeType); {后序遍历算法}begini:=Leftmost_Child(v);while i<>∧ dobeginPreorder_Traversal(i);{从左到右依次访问v的每一个儿子节点i}i:=Right_Sibling(i);end;Visite(v); {访问节点v}end;
收起全文
精华内容
下载资源
问答
  • 三叉树多叉树遍历

    2015-04-21 17:50:14
    三叉树多叉树遍历 c# 2.0
  • 语法树遍历

    2015-11-14 10:42:12
    尝试设计翻译方法。假定对程序片段已得到语法,如 if (a > b) b = a; 已得到语法 编写程序,遍历语法,执行代码,得到正确结果。
  • 建立一棵二叉链表,分别输出此先根、中根和后根遍历序列 将上题编程,实现哈夫曼的构建和哈夫曼编码的设计
  • 本篇是给大家介绍的Python实现解析以及实现二叉树的三种遍历,先序遍历,中序遍历,后序遍历的例子,非常的详细,有需要的小伙伴可以参考下。
  • 主要介绍了Java二叉搜索树遍历操作,结合实例形式详细分析了Java二叉搜索树前序、中序、后序、层次、广度优先遍历等相关原理与操作技巧,需要的朋友可以参考下
  • 基于数组实现的树遍历方法

    千次阅读 2021-03-06 13:28:45
    二叉查找(Binary Search Tree),(又:二叉搜索,二叉排序)。 二叉排序的性质        若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子...

    Binary Search Tree

           二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)。

    二叉排序树的性质

           若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

    1. 即按照左子树<根<右子树
    2. 满二叉树常常用数组来存储

    ## 基于数组实现的树遍历方法        如下图所示二叉树,若讲其存在数组中,其并不是该树所展示的样子,并且也并非有序的,不过由于BST的性质可知,其中序遍历即有序的。

    在这里插入图片描述
           其数组中存放如下,对于链式的树结构比较直观,对于数组该如何处理呢?
    在这里插入图片描述

    数组中序遍历

           此处需要明白数组表示树的相关性质。

    1. 如根位置索引为x, 左孩子=2x+1, 右孩子=2x+2
    2. 若节点位置索引为n,数组length为l,若n>=1/2,则该节点位置为叶子节点(数组的索引位置都是从0开始)
    public static void pre(List<Integer> result, int[] source,int root){
        if (root<source.length){
            //左孩子 root*2+1
            if (root*2+1<source.length)
                pre(result,source,root*2+1);
            result.add(source[root]);
            if (root*2+2<source.length)
                pre(result,source,root*2+2);
        }
    }
    
    1. 测试,可见BST中序遍历即有序的。
    public static void main(String[] args) {
        int[] source = new int[]{12,5,18,2,9,15,19};
        List<Integer> result = new ArrayList<>();
        pre(result,source,0);
        System.err.println(result);
    }
    

    在这里插入图片描述

    展开全文
  • 本文实例讲述了JavaScript实现的DOM树遍历方法。分享给大家供大家参考,具体如下: 二叉 DOM 树的遍历 function Tree() { var Node = function(key){ this.key = key; this.left = null; this.right = null; }...
  • B+树遍历与查找

    千次阅读 多人点赞 2019-08-30 09:32:18
    这一次我们来介绍 B+ 。 一个m阶的B具有如下几个特征: 1.根结点至少有两个子女。 2.每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m 3.每一个叶子节点都包含k-1个元素,其中 m/2 ...

    这一次我们来介绍 B+ 树。

    一个m阶的B树具有如下几个特征:

    1.根结点至少有两个子女。

    2.每个中间节点都包含k-1个元素和k个孩子,其中 m/2 <= k <= m

    3.每一个叶子节点都包含k-1个元素,其中 m/2 <= k <= m

    4.所有的叶子结点都位于同一层。

    5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。

    一个m阶的B+树具有如下几个特征:

    1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。

    2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

    3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。

    B-树中的卫星数据(Satellite Information):

    B+树中的卫星数据(Satellite Information):

    需要补充的是,在数据库的聚集索引(Clustered Index)中,叶子节点直接包含卫星数据。在非聚集索引(NonClustered Index)中,叶子节点带有指向卫星数据的指针。

    第一次磁盘IO:

    第二次磁盘IO:

    第三次磁盘IO:

    B-树的范围查找过程

    自顶向下,查找到范围的下限(3):

    中序遍历到元素6:

    中序遍历到元素8:

    中序遍历到元素9:

    中序遍历到元素11,遍历结束:

    B+树的范围查找过程

    自顶向下,查找到范围的下限(3):

    通过链表指针,遍历到元素6, 8:

    通过链表指针,遍历到元素9, 11,遍历结束:

    B+树的特征:

    1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。

    2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

    3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。

    B+树的优势:

    1.单一节点存储更多的元素,使得查询的IO次数更少。

    2.所有查询都要查找到叶子节点,查询性能稳定。

    3.所有叶子节点形成有序链表,便于范围查询。

    展开全文
  • 树遍历及二叉树.ppt

    2020-10-30 04:19:51
    树遍历及二叉树.ppt
  • 一、权限是什么 在写项目的权限管理模块、用户系统的时候经常碰见类似的结构我们一般习惯称之为权限,权限应用的地方有很多,比较常见的有:权限管理时候的树状图(如上图),页面左侧的一二三级的菜单,...

    一、权限树是什么

            在写项目的权限管理模块、用户系统的时候经常碰见类似的树结构我们一般习惯称之为权限树,权限树应用的地方有很多,比较常见的有:权限管理时候的树状图(如上图),页面左侧的一二三级的菜单,物品分类的树状菜单。

    在实际项目中这种权限结构,数据库设计一般是这样的:


            其中我们需要通过id和父id来遍历树状图,这种结构非常简单也很好理解,但对于新手编码来说就不是特别的友好了,特别是培训出来的朋友可能对数据结构和算法不是特别了解,经常性会参考网上一些不是很优秀的写法,通过递归的方式反复的查询数据库来逐层往上级遍历,这种写法的运行起来比较慢,网络开销比较大,如下图:


    二、如何遍历权限树

    下面我们一起思考如何写一个权限树的遍历并且让其适用与大部分情况

    ps:完整代码https://github.com/guoyixing/converttree

    1、设计结构

    根据上文数据库,可以设计出一个简单有效的结构:

    data:数据库表的任意一行权限

    childrenNode:data节点下所有的权限集合

    然后添加上get、set方法,为了方便再增加两个构造函数,用于对元素初始化(空构造函数也不忘记),因为我们无法得知data具体是什么类型,所有使用泛型让data可以成为任何类,增加通用性。

    public class TreeNode<T> {
        //数据内容
        private T data;
        //这个节点下的子节点
        private List<TreeNode<T>> childrenNode = new ArrayList<>();
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    
        public List<TreeNode<T>> getChildrenNode() {
            return childrenNode;
        }
    
        public void setChildrenNode(List<TreeNode<T>> childrenNode) {
            this.childrenNode = childrenNode;
        }
    
        public TreeNode(T data, List<TreeNode<T>> childrenNode) {
            this.data = data;
            this.childrenNode = childrenNode;
        }
    
        public TreeNode() {
        }
    }



    2、获取权限数据

            之前说到反复的去数据库获取数据会让网络开销变大,所以我们应该一次性将所有需要的权限数据全部取出(有的时候是取出全部的数据,有时取得某个角色的权限数据),将取到数据放入一个list中。

    一个节点类应该还具有获取自己子节点的能力,在TreeNode类中添加获取子节点方法:

    通过data的id和每条数据的父id对比相同的放入子节点的集合中,并且从数据集合中删除(这样做只要权限数据集合变成空了就可以算是树遍历完成)

    public List<TreeNode<T>> childrenNode(List<T> datas, String idName, String fidName) {
            ConvertTree<T> convertTree = new ConvertTree<>();
            String idValue = convertTree.getFieldValue(data, idName);
            List<T> collect = datas.stream()
                    .filter(date -> idValue.equals(convertTree.getFieldValue(date, fidName)))
                    .collect(Collectors.toList());
            datas.removeAll(collect);
            for (T node : collect) {
                TreeNode<T> treeNode = new TreeNode<>();
                treeNode.setData(node);
                childrenNode.add(treeNode);
            }
            return childrenNode;
        }

    由于无法知道具体的类也就不知道id字段和父id字段,采用反射的方式获取字段的值

    public String getFieldValue(T o, String fieldName) {
            //得到class
            Class cls = o.getClass();
            //得到所有属性
            Field[] fields = cls.getDeclaredFields();
            for (Field field : fields) {
                try {
                    //打开私有访问
                    field.setAccessible(true);
                    //获取属性
                    if (field.getName().equals(fieldName)) {
                        Object result = field.get(o);
                        if (result == null) {
                            return null;
                        }
                        return result.toString();
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            throw new RuntimeException("获取属性值失败");
        }

    3、从数据中找出根节点

            我们首先需要定位一棵树最顶端的节点,也就是根节点“祖宗节点”。

    新建一个类,并添加获取根节点方法。这个方法需要权限数据的集合,id的字段名,父id的字段名

    思路:判断权限集合是否为空,取出集合中第一个元素,用过递归一层一层往上找,一直到找不到父节点为止,将这个得到的根节放到我们的树结构中,并且通过childrenNode来获取子节点他的子节点。

    private TreeNode<T> getRootNode(List<T> datas, String idName, String fidName) {
            if (datas.isEmpty()) {
                return null;
            }
            T node = datas.get(0);
            T rootNode = getRootNode(datas, idName, fidName, node);
            TreeNode<T> rootTreeNode = new TreeNode<>();
            datas.remove(rootNode);
            rootTreeNode.setData(rootNode);
            rootTreeNode.childrenNode(datas, idName, fidName);
            return rootTreeNode;
        }

    这个方法会不停的递归直到早不到父节点为止

    private T getRootNode(List<T> datas, String idName, String fidName, T node) {
            T fNode = null;
            String fieldValue = getFieldValue(node, fidName);
            for (T data : datas) {
                if (getFieldValue(data, idName).equals(fieldValue)) {
                    fNode = data;
                    break;
                }
            }
            if (fNode == null) {
                return node;
            } else {
                return getRootNode(datas, idName, fidName, fNode);
            }
        }

    4、根据根节点形成一棵树

    先获取根节点,然后使用forChildren方法遍历根节点的子集,一级一级的往下查找子级,最后返回树。

    private TreeNode<T> getTree(List<T> datas, String idName, String fidName) {
            //获取树根
            TreeNode<T> rootNode = getRootNode(datas, idName, fidName);
            //遍历树根的子集
            List<TreeNode<T>> childrenNode = rootNode.getChildrenNode();
            forChildren(datas, idName, fidName, childrenNode);
            //此时树已经形成
            return rootNode;
        }

    遍历子集,将子集的子集记录下来,存入needForList,如果needForList不为空就一直递归,needForList为空的时候说明这棵树的所有相关的节点都找到了并且都通过childrenNode方法处理成TreeNode类。

    private void forChildren(List<T> datas, String idName, String fidName, List<TreeNode<T>> childrenNode) {
            //需要遍历的集合
            List<TreeNode<T>> needForList = new ArrayList<>();
            for (TreeNode<T> tTreeNode : childrenNode) {
                List<TreeNode<T>> treeNodes = tTreeNode.childrenNode(datas, idName, fidName);
                needForList.addAll(treeNodes);
            }
            if (!needForList.isEmpty()) {
                forChildren(datas, idName, fidName, needForList);
            }
        }

    三、形成森林

    很多时候权限树并没有一个统一的根节点,如下图:


    系统管理、软件管理、统计分析各是一棵树,这时候我们就需要把每一棵树都遍历出来,添加形成森林的方法:

    只需要循环执行形成树的方法,一直到所有的权限数据的集合为空的时候结束,将所有的遍历出来的树放入集合中,返回集合。

    public List<TreeNode<T>> getForest(List<T> datas, String idName, String fidName) {
            List<TreeNode<T>> forest = new ArrayList<>();
            while (!datas.isEmpty()) {
                TreeNode<T> tree = getTree(datas, idName, fidName);
                forest.add(tree);
            }
            return forest;
        }

    四、使用

    1.仅支持java8,id不可重复

    2.调用方法就可以使用了

    public List<TreeNode<AuthResource>> toTree() {
            //获取数据集合
            List<AuthResource> list = authResourceRepository.findAll();
            //创建工具类
            ConvertTree<AuthResource> convertTree = new ConvertTree<>();
            //生成森林
            List<TreeNode<AuthResource>> forest = convertTree.getForest(list, "id", "parentId");
            return convertTree.getForest(list);
        }

    3.如果上面代码复制后无法使用,到这里下载https://github.com/guoyixing/converttree

    未经同意不得转载,如有发现必定追责,非商业使用无需经过同意。

    展开全文
  • 红黑问题是各大计算机考研命题以及面试算法题目中的热门,接下来我们为大家图解红黑及Java进行红黑二叉树遍历的方法,需要的朋友可以参考下
  • ANTLR教程(四)语法树遍历机制

    万次阅读 2017-10-05 15:11:27
    1. 方法一: 使用antlr定义的语法树遍历顺序——listener1.1. 类的继承关系 1.2. 需要与antlr遍历类ParseTreeWalker一起使用 1.3. 对同一非终结符的不同产生式进行标记1.3.1. 不标记的话实现起来复杂 1.3.2. 解决方法...
     
    

    方法一: 使用antlr定义的语法树遍历顺序——listener

    antlr生成类ParseTreeListener,这个类里面包含了进入语法树种每个节点和退出每个节点时要进行的操作。本质上,就是树的前序和后序遍历。

    类的继承关系

    这里写图片描述

    1. ANTLR自动生成 XXXListener接口,在类xxxBaseListener中实现所有的方法
    2. 程序员需要做的是集成xxxxBaseListener类

    需要与antlr遍历类ParseTreeWalker一起使用

    对同一非终结符的不同产生式进行标记

    不标记的话实现起来复杂

    listeners/Expr.g4
    grammar Expr;
    s:e;
    e:eop=MULTe //MULTis’*’

    e op=ADD e // ADD is ‘+’INT

    ;

    1. listener需要判断哪个e
      listeners/TestEvaluator.java
      public void exitE(ExprParser.EContext ctx) {
      if ( ctx.getChildCount()==3 ) { // operations have 3 children
      int left = values.get(ctx.e(0));
      int right = values.get(ctx.e(1));
      if ( ctx.op.getType()==ExprParser.MULT ) {
      values.put(ctx, left * right);
      }
      else {
      values.put(ctx, left + right);
      } }
      else {
      values.put(ctx, values.get(ctx.getChild(0))); // an INT
      } }
    2. 上下文EContext将三个可选择的产生式放到了同一个上下文
      public static class EContext extends ParserRuleContext {
      public Token op;// derived from label op
      public List e() { … } */ get all e subtrees
      public EContext e(int i) { … } /* get ith e subtree
      public TerminalNode INT() { … } // get INT node if alt 3 of e

      }

    解决方法: 标记产生式

    e : e MULT e # Mult

    e ADD e # Add
    INT # Int

    ;

    1. ANTLR为每个产生式生成函数
      public interface LExprListener extends ParseTreeListener { void enterMult(LExprParser.MultContext ctx);
      void exitMult(LExprParser.MultContext ctx);
      void enterAdd(LExprParser.AddContext ctx);
      void exitAdd(LExprParser.AddContext ctx); void enterInt(LExprParser.IntContext ctx); void exitInt(LExprParser.IntContext ctx); …
      }
    2. ANTLR 生成特定的上下文对象,EContext的子类
    3. IntContext has only an INT() method

    特点

    1. 程序员不需要显示定义遍历语法树的顺序,实现简单
    2. 缺点,也是不能显示控制遍历语法树的顺序,visit方式可以
    3. 动作代码与文法产生式解耦,利于文法产生式的重用
    4. 没有返回值,需要使用map、栈等结构在节点间传值

    例子

    这里写图片描述
    语法树遍历时,函数调用顺序
    这里写图片描述

    方法二: 程序员需要自定义语法树遍历顺序——visit

    类的继承关系

    这里写图片描述

    特点

    1. 程序员可以显示定义遍历语法树的顺序
    2. 不需要与antlr遍历类ParseTreeWalker一起使用,直接对tree操作
    3. 动作代码与文法产生式解耦,利于文法产生式的重用
    4. visitor方法可以直接返回值,返回值的类型必须一致,不需要使用map这种节点间传值方式,效率高

    例子

    这里写图片描述

    PropertyFileVisitor loader = new PropertyFileVisitor();
    loader.visit(tree);
    System.out.println(loader.props); // print results

    方法三: 将动作代码嵌入文法产生式文法

    不利于文法产生式在不同的语言中重用

    展开全文
  • 树遍历的应用——树的重建 问题描述:现有两个结点序列,分别是对同一个二叉树进行前序遍历和中序遍历。请输出该二叉树的后序遍历。   输入:第一行输入二叉树的结点数。  第二行输入前序遍历的结点编号序列,...
  • JS遍历实例

    2017-05-24 23:31:01
    js 实现形数据结构遍历[前序,后续];实现形节点移动,任然保持形结构;
  • Java递归遍历树形结构

    2020-09-02 16:42:25
    主要介绍了Java递归遍历树形结构的相关资料,需要的朋友可以参考下
  • 迭代树遍历 树遍历算法的迭代实现
  • java多叉的实现:节点集合生成多叉,单个节点添加到多叉,深度遍历,广度遍历
  • NULL 博文链接:https://128kj.iteye.com/blog/1734260
  • javascript实现数据结构: 和二叉树,二叉树的遍历和基本操作 树型结构是一类非常重要的非线性结构。直观地,树型结构是以分支关系定义的层次结构。 在计算机领域中也有着广泛的应用,例如在编译程序中,用来...
  • 哈夫曼创建遍历

    2012-09-18 13:12:21
    程序代码包括创建二叉树,遍历树,创建哈夫曼,打印哈夫曼叶子节点的路径。
  • java实现遍历

    2020-08-04 12:29:25
    是一种经常用到的数据结构,用来模拟具有树状结构性质的数据集合。 里的每一个节点有一个值和一个包含所有子节点的列表。从图的观点来看,也可视为一个...遍历分为前序遍历、中序遍历、后序遍历。 ...
  • class TreeNode(object): ...###递归的形式 先序遍历 中序遍历 后序遍历 def preOrderRecursive(root): if root == None: return None print(root.val) preOrderRecursive(root.left) preOrderRecursive(root
  • java多叉遍历

    千次阅读 2019-01-23 08:54:26
    用过了二叉树后,正好业务上有一个需求,就是需要求出从根节点到每个叶子节点的路径集合,由于不是二叉树,而是如同一种多叉的结构,下面来看具体代码, 1、节点对象,包含3个属性,当前节点Id,持有的父节点Id,...
  • 利用MySQL存储过程实现的初始化、插入、深度遍历、按层遍历、删除操作。可以作为学习存储过程的笑demo
  • C++用递归算法实现二叉树的前序、中序、后序遍历,用队列实现层次遍历
  • 多叉的建立以及后序非递归遍历,希望对学习数据结构的同学有所帮助,也对一部分有更深的了解。
  • 多叉遍历

    2020-06-22 21:28:17
    429. N叉的层序遍历 给定一个 N 叉,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。 返回其层序遍历: [ [1], [3,2,4], [5,6] ] 说明: 的深度不会超过 1000。 的节点总数不会超过 5000。 class ...
  • C++用非递归算法(用栈实现前序、中序、后序遍历;用队列实现层次遍历)实现二叉树的遍历

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 501,071
精华内容 200,428
关键字:

树的遍历