树的递归与非递归遍历总结

  树的递归遍历遍历很简单,非递归遍历要复杂一些,非递归先序、中序、后序遍历需要用一个辅助栈,而层次遍历则需要一个辅助队列。

  树的结构:

1 public class Tree<T> {
2     private T data;
3     private Tree<T> left;
4     private Tree<T> right;
5         ...
6 }

  用策略模式定义一个访问工具:

1 public interface Visitor<T> {
2         void process(T data);
3     }

  先上递归访问方法:

 1    /**
 2      * 递归中序遍历
 3      *
 4      * @param visitor
 5      */
 6     public void recursionInOrder(Visitor<T> visitor) {
 7         if (left != null)// 如果左子树存在,先访问左子树
 8             left.recursionInOrder(visitor);
 9         visitor.process(data);// 访问当前结点
10         if (right != null)// 如果右子树存在,访问右子树
11             right.recursionInOrder(visitor);
12     }
13
14     /**
15      * 递归先序遍历
16      *
17      * @param visitor
18      */
19     public void recursionPreOrder(Visitor<T> visitor) {
20         visitor.process(data);// 访问当前结点
21         if (left != null)// 如果左子树存在,访问左子树
22             left.recursionPreOrder(visitor);
23         if (right != null)// 如果右子树存在,访问右子树
24             right.recursionPreOrder(visitor);
25     }
26
27     /**
28      * 递归后序遍历
29      *
30      * @param visitor
31      */
32     public void recursionPostOrder(Visitor<T> visitor) {
33         if (left != null)// 如果左子树存在,先访问左子树
34             left.recursionInOrder(visitor);
35         if (right != null)// 如果右子树存在,访问右子树
36             right.recursionInOrder(visitor);
37         visitor.process(data);// 访问当前结点
38     }

  层次遍历,使用一个辅助队列,以便逐层访问:  

 1     /**
 2      * 层次遍历
 3      *
 4      * @param visitor
 5      */
 6     public void levelViste(Visitor<T> visitor) {
 7         Queue<Tree<T>> queue = new LinkedList<Tree<T>>();
 8         queue.add(this);
 9         while (!queue.isEmpty()) {
10             Tree<T> node = queue.poll();
11             visitor.process(node.data);
12             if (node.left != null)
13                 queue.add(node.left);
14             if (node.right != null)
15                 queue.add(node.right);
16         }
17     }

  非递归的先序与中序遍历差别很小,唯一不同之处是先序在把结点放入栈前就访问了,而中序是在结点出栈的时候访问。

 1 /**
 2      * 先序遍历
 3      *
 4      * @param visitor
 5      */
 6     public void preOrderViste(Visitor<T> visitor) {
 7         Stack<Tree<T>> stack = new Stack<Tree<T>>();
 8         Tree<T> node = this;
 9         while (node != null || !stack.isEmpty()) {
10             if (node != null) {// 向左走到尽头
11                 visitor.process(node.data);
12                 stack.add(node);
13                 node = node.left;
14             } else {
15                 node = stack.pop();
16                 node = node.right;
17             }
18         }
19     }
20
21     /**
22      * 中序遍历
23      *
24      * @param visitor
25      */
26     public void inOrderViste(Visitor<T> visitor) {
27
28         Stack<Tree<T>> stack = new Stack<Tree<T>>();
29         Tree<T> node = this;
30         while (node != null || !stack.isEmpty()) {
31             if (node != null) {// 向左走到尽头
32                 stack.add(node);
33                 node = node.left;
34             } else {
35                 node = stack.pop();
36                 visitor.process(node.data);
37                 node = node.right;
38             }
39
40         }
41     }

  后续遍历略微复杂一些,因为根结点要最后访问,需要知道回溯是来自左孩子还是右孩子,因此需要记录上一次访问的结点。

 1   /**
 2      * 后续遍历
 3      *
 4      * @param visitor
 5      */
 6     public void postOrderViste(Visitor<T> visitor) {
 7         Stack<Tree<T>> stack = new Stack<Tree<T>>();
 8         Tree<T> node = this, last = null;
 9         while (node != null || !stack.isEmpty()) {
10             if (node != null) {// 向左走到尽头
11                 stack.add(node);
12                 node = node.left;
13             } else {
14                 node = stack.peek();
15                 if (node.right != null && node.right != last) {// 有右孩子
16                     node = node.right;// 向右走一步
17                     stack.add(node);
18                     node = node.left;// 向左走到尽头
19                 } else {// 访问结点
20                     node = stack.pop();
21                     visitor.process(node.data);
22                     last = node;
23                     node = null;// 置为空,强制去探索右孩子
24                 }
25             }
26         }
27     }

  测试:

 1 private static Visitor<Integer> visitor = new Visitor<Integer>() {
 2         @Override
 3         public void process(Integer data) {
 4             System.out.print(data + " ");
 5         }
 6     };
 7
 8     /**
 9      * 根据方法名测试访问
10      *
11      * @param tree
12      * @param method
13      * @param visitor
14      * @throws Exception
15      */
16     private static void test(Tree<?> tree, String method, Visitor<?> visitor)
17             throws Exception {
18         Class<?> c = (Class<?>) Class.forName("tree.Tree");
19         Method func = c.getDeclaredMethod(method, Visitor.class);
20         func.invoke(tree, visitor);
21         System.out.println("(" + method + ")");
22
23     }
24
25     public static void main(String[] args) throws Exception {
26         Integer[] datas = { 0, 1, 2, 3, 4, 5, 6, 7 };
27         Tree<Integer> tree = new Tree<Integer>(datas);
28         test(tree, "preOrderViste", visitor);
29         test(tree, "inOrderViste", visitor);
30         test(tree, "postOrderViste", visitor);
31         test(tree, "inOrderViste", visitor);
32         test(tree, "recursionInOrder", visitor);
33         test(tree, "recursionPreOrder", visitor);
34         test(tree, "recursionPostOrder", visitor);
35         test(tree, "levelViste", visitor);
36     }

  完整的代码折叠起来了:

  1 public class Tree<T> {
  2     private T data;
  3     private Tree<T> left;
  4     private Tree<T> right;
  5
  6     private Tree(T data) {
  7         this.data = data;
  8
  9     }
 10
 11     public Tree(T[] datas) {
 12         makeTree(datas, this);
 13     }
 14
 15     public interface Visitor<T> {
 16         void process(T data);
 17     }
 18
 19     /**
 20      * 递归中序遍历
 21      *
 22      * @param visitor
 23      */
 24     public void recursionInOrder(Visitor<T> visitor) {
 25         if (left != null)// 如果左子树存在,先访问左子树
 26             left.recursionInOrder(visitor);
 27         visitor.process(data);// 访问当前结点
 28         if (right != null)// 如果右子树存在,访问右子树
 29             right.recursionInOrder(visitor);
 30     }
 31
 32     /**
 33      * 递归先序遍历
 34      *
 35      * @param visitor
 36      */
 37     public void recursionPreOrder(Visitor<T> visitor) {
 38         visitor.process(data);// 访问当前结点
 39         if (left != null)// 如果左子树存在,访问左子树
 40             left.recursionPreOrder(visitor);
 41         if (right != null)// 如果右子树存在,访问右子树
 42             right.recursionPreOrder(visitor);
 43     }
 44
 45     /**
 46      * 递归后序遍历
 47      *
 48      * @param visitor
 49      */
 50     public void recursionPostOrder(Visitor<T> visitor) {
 51         if (left != null)// 如果左子树存在,先访问左子树
 52             left.recursionInOrder(visitor);
 53         if (right != null)// 如果右子树存在,访问右子树
 54             right.recursionInOrder(visitor);
 55         visitor.process(data);// 访问当前结点
 56     }
 57
 58     /**
 59      * 层次遍历
 60      *
 61      * @param visitor
 62      */
 63     public void levelViste(Visitor<T> visitor) {
 64         Queue<Tree<T>> queue = new LinkedList<Tree<T>>();
 65         queue.add(this);
 66         while (!queue.isEmpty()) {
 67             Tree<T> node = queue.poll();
 68             visitor.process(node.data);
 69             if (node.left != null)
 70                 queue.add(node.left);
 71             if (node.right != null)
 72                 queue.add(node.right);
 73         }
 74     }
 75
 76     /**
 77      * 先序遍历
 78      *
 79      * @param visitor
 80      */
 81     public void preOrderViste(Visitor<T> visitor) {
 82         Stack<Tree<T>> stack = new Stack<Tree<T>>();
 83         Tree<T> node = this;
 84         while (node != null || !stack.isEmpty()) {
 85             if (node != null) {// 向左走到尽头
 86                 visitor.process(node.data);
 87                 stack.add(node);
 88                 node = node.left;
 89             } else {
 90                 node = stack.pop();
 91                 node = node.right;
 92             }
 93         }
 94     }
 95
 96     /**
 97      * 中序遍历
 98      *
 99      * @param visitor
100      */
101     public void inOrderViste(Visitor<T> visitor) {
102
103         Stack<Tree<T>> stack = new Stack<Tree<T>>();
104         Tree<T> node = this;
105         while (node != null || !stack.isEmpty()) {
106             if (node != null) {// 向左走到尽头
107                 stack.add(node);
108                 node = node.left;
109             } else {
110                 node = stack.pop();
111                 visitor.process(node.data);
112                 node = node.right;
113             }
114         }
115     }
116
117     /**
118      * 后续遍历
119      *
120      * @param visitor
121      */
122     public void postOrderViste(Visitor<T> visitor) {
123         Stack<Tree<T>> stack = new Stack<Tree<T>>();
124         Tree<T> node = this, last = null;
125         while (node != null || !stack.isEmpty()) {
126             if (node != null) {// 向左走到尽头
127                 stack.add(node);
128                 node = node.left;
129             } else {
130                 node = stack.peek();
131                 if (node.right != null && node.right != last) {// 有右孩子
132                     node = node.right;// 向右走一步
133                     stack.add(node);
134                     node = node.left;// 向左走到尽头
135                 } else {// 访问结点
136                     node = stack.pop();
137                     visitor.process(node.data);
138                     last = node;
139                     node = null;// 置为空,强制去探索右孩子
140                 }
141             }
142         }
143     }
144
145     /**
146      * 构造一个满二叉树
147      *
148      * @param datas
149      * @param root
150      */
151     public void makeTree(T[] datas, Tree<T> root) {
152         List<Tree<T>> trees = new ArrayList<Tree<T>>(datas.length);
153         root.data = datas[0];
154         trees.add(root);
155         for (int i = 1; i < datas.length; i++) {
156             trees.add(new Tree<T>(datas[i]));
157         }
158         int level = (int) (Math.log(datas.length) / Math.log(2));
159         for (int i = 0; i <= level; i++) {
160             int left = i * 2 + 1;
161             if (left < datas.length)
162                 trees.get(i).left = trees.get(left);
163             int right = i * 2 + 2;
164             if (right < datas.length)
165                 trees.get(i).right = trees.get(right);
166         }
167     }
168
169     private static Visitor<Integer> visitor = new Visitor<Integer>() {
170         @Override
171         public void process(Integer data) {
172             System.out.print(data + " ");
173         }
174     };
175
176     /**
177      * 根据方法名测试访问
178      *
179      * @param tree
180      * @param method
181      * @param visitor
182      * @throws Exception
183      */
184     private static void test(Tree<?> tree, String method, Visitor<?> visitor)
185             throws Exception {
186         Class<?> c = (Class<?>) Class.forName("tree.Tree");
187         Method func = c.getDeclaredMethod(method, Visitor.class);
188         func.invoke(tree, visitor);
189         System.out.println("(" + method + ")");
190
191     }
192
193     public static void main(String[] args) throws Exception {
194         Integer[] datas = { 0, 1, 2, 3, 4, 5, 6, 7 };
195         Tree<Integer> tree = new Tree<Integer>(datas);
196         test(tree, "preOrderViste", visitor);
197         test(tree, "inOrderViste", visitor);
198         test(tree, "postOrderViste", visitor);
199         test(tree, "inOrderViste", visitor);
200         test(tree, "recursionInOrder", visitor);
201         test(tree, "recursionPreOrder", visitor);
202         test(tree, "recursionPostOrder", visitor);
203         test(tree, "levelViste", visitor);
204     }
205 }

  转载请注明出处:http://www.cnblogs.com/fengfenggirl

树的递归与非递归遍历总结,布布扣,bubuko.com

时间: 2024-10-25 07:48:19

树的递归与非递归遍历总结的相关文章

数据结构之关于树的操作(树的递归和非递归遍历)-(四补)

前面写了一些关于树的操作,但是没有实现树的遍历的非递归写法. 通常树有四种遍历方法:1.层次遍历(需要用到树的高度,此文没有考虑) 2.前序遍历(根左右):3.中序遍历(左根右):4.后序遍历(左右根) 树的结构如下: 层次遍历:123456789 前序遍历:124895367 中序遍历:849251637 后序遍历:894526731 java代码实现三种遍历的递归和和非递归实现 package com.lip.datastructure.tree; import java.util.Stac

[转] 树的递归与非递归遍历

1 public class Tree<T> { 2 private T data; 3 private Tree<T> left; 4 private Tree<T> right; 5 6 private Tree(T data) { 7 this.data = data; 8 9 } 10 11 public Tree(T[] datas) { 12 makeTree(datas, this); 13 } 14 15 public interface Visitor

(源码,具体的细节请查阅相关资料)哈弗曼树的构造以及非递归遍历树

写了一点haffman树的创建和二叉树的非递归遍历. 如果编写代码的时候出现了,思维断点,可以借鉴一下, 避免浪费一些不必要的时间. 我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占 位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我 是占位符我是占位符我是占位符我是占位符我是占位符我是 占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符我是占位符

Java数据结构系列之——树(4):二叉树的中序遍历的递归与非递归实现

package tree.binarytree; import java.util.Stack; /** * 二叉树的中序遍历:递归与非递归实现 * * @author wl * */ public class BiTreeInOrder { // 中序遍历的递归实现 public static void biTreeInOrderByRecursion(BiTreeNode root) { if (root == null) { return; } biTreeInOrderByRecursi

Java数据结构系列之——树(5):二叉树的后序遍历的递归与非递归实现

package tree.binarytree; import java.util.Stack; /** * 二叉树后序遍历的递归与非递归实现 * * @author wl * */ public class BitreePostOrder { // 后序遍历的递归实现 public static void biTreePostOrderByRecursion(BiTreeNode root) { if (root == null) { return; } biTreePostOrderByRe

二叉树的前序、中序、后序遍历(递归、非递归)实现

本文部分来源于CSDN兰亭风雨大牛的原创.链接为http://blog.csdn.net/ns_code/article/details/12977901 二叉树是一种非常重要的数据结构,很多其他数据机构都是基于二叉树的基础演变过来的.二叉树有前.中.后三种遍历方式,因为树的本身就是用递归定义的,因此采用递归的方法实现三种遍历,不仅代码简洁且容易理解,但其开销也比较大,而若采用非递归方法实现三种遍历,则要用栈来模拟实现(递归也是用栈实现的).下面先简要介绍三种遍历方式的递归实现,再详细介绍三种遍

C实现二叉树(模块化集成,遍历的递归与非递归实现)

C实现二叉树模块化集成 实验源码介绍(源代码的总体介绍):header.h : 头文件链栈,循环队列,二叉树的结构声明和相关函数的声明.LinkStack.c : 链栈的相关操作函数定义.Queue.c : 循环队列的相关操作函数定义.BinTree.c : 二叉树的相关操作的函数定义,层序序列生成二叉树,二叉树的前序序列.中序序列.后序序列的递归和非递归实现,求叶子结点的递归与非递归实现,求树高.我目前还是新手且第一次写类似的博客,文章中难免会有错误!如发现错误,望各路大神能够指出!详见源代码

二叉树的广度优先遍历、深度优先遍历的递归和非递归实现方式

二叉树的遍历方式: 1.深度优先:递归,非递归实现方式 1)先序遍历:先访问根节点,再依次访问左子树和右子树 2)中序遍历:先访问左子树,再访问根节点吗,最后访问右子树 3)后序遍历:先访问左子树,再访问右子树,最后访问根节点 2.广度优先     按照树的深度,一层一层的访问树的节点 1 package Solution; 2 3 import java.util.LinkedList; 4 import java.util.Queue; 5 import java.util.Stack; 6

数据结构二叉树的递归与非递归遍历之 实现可编译(1)java

前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序遍历为例进行说明,中序遍历和后序遍历,以此类推! 二叉树递归与非递归遍历的区别,虽然递归遍历,跟容易读懂,代码量少,运算快,但是却容易出现溢出的问题,所以所以非递归遍历,在处理千万级的运算量时会先的很有用处. 二叉树的先序遍历:先访问根节点,再访问先后访问左右节点.如图: 二叉树的递归遍历之java