遍历二叉树的三种方法

朋友面试遇到一道笔试题:写出递归遍历二叉树的代码(先序、中序、后序遍历都可以)?

首先要知道二叉树是什么,它的数据结构是怎样的?

如何实现这种二叉树?采用匿名内部类的形式实现

class Node{
        //节点数据
        private T data;     //可比较的泛型
        //左子树
        private Node leftChildTree;
        //右子树
        private Node rightChildTree;

        public Node(T data){
            this.data = data;
        }
    }

知道它的数据类型就容易对其进行遍历

//前序遍历
    public void preorderTraversal(Node root){
        if (root == null){
            return;
        }
        System.out.println("node = [" + root.data + "]");
        preorderTraversal(root.leftChildTree);
        preorderTraversal(root.rightChildTree);
    }
    //中序遍历
    public void inorderTraversal(Node root){
        if (root == null){
            return;
        }
        inorderTraversal(root.leftChildTree);
        System.out.println("node = [" + root.data + "]");
        inorderTraversal(root.rightChildTree);
    }

    //后续遍历
    public void postorderTraversal(Node root){
        if (root == null){
            return;
        }
        postorderTraversal(root.leftChildTree);
        postorderTraversal(root.rightChildTree);
        System.out.println("node = [" + root.data + "]");
    }

但真的这么简单么?

数据结构和算法问题,解决问题只是看储备知识的广度,优化问题才是看能力素质的高度

栈模拟递归的非递归算法:这样算法空间复杂度为O(h),h为二叉树的高度

//前序遍历
    public void preorderTraversal(Node root){
        if (root == null){
            return;
        }
        Stack<Node> stack = new Stack<Node>();
        stack.push(root);
        while (!stack.empty()){

            Node node = stack.pop();
            System.out.println("node = [" + node.data + "]");
            if (root.rightChildTree != null) stack.push(root.rightChildTree);
            if (root.leftChildTree != null) stack.push(root.leftChildTree);
        }

    }
    //中序遍历
    public void inorderTraversal(Node root){
        if (root == null){
            return;
        }
        Stack<Node> stack = new Stack<Node>();
        Stack<Node> stack2 = new Stack<Node>();

        stack.push(root);
        while (!stack.empty()){

            if (root.rightChildTree != null) stack.push(root.rightChildTree);
            Node node = stack.pop();
            stack2.push(node);
            if (root.leftChildTree != null) stack.push(root.leftChildTree);
        }
        while(!stack2.empty())
        {
            Node node2 = stack2.pop();
            System.out.println("node = [" + node2.data + "]");
        }
    }

    //后续遍历
    public void postorderTraversal(Node root){
        if (root == null) return;

        Stack<Node> stack = new Stack<Node>();
        Stack<Node> stack2 = new Stack<Node>();
        stack.push(root);
        while (!stack.empty())
        {
            Node node = stack.pop();
            stack2.push(node);
            if (root.rightChildTree != null) stack.push(root.rightChildTree);
            if (root.leftChildTree != null) stack.push(root.leftChildTree);
        }
        while(!stack2.empty())
        {
            Node node2 = stack2.pop();
            System.out.println("node = [" + node2.data + "]");
        }
    }

Morris遍历的神奇之处在于它是非递归的算法,但并不需要额外的O(h)的空间,而且复杂度仍然是线性的。

Morrs遍历优势:O(1)空间复杂度;二叉树的形状不被破坏

1、先找到根节点的左子树的最右节点,让最右节点的右子树指向根节点。(本来最右节点的右子树是null,将根节点复制给它)

4、以左子树的根节点的为根节点,继续1步骤。

3、然后中序遍历:当左子树为空时,打印输出,

         当节点指向的右子树等于根节点时,说明此节点为根节点左子树的最右节点,打印根节点,遍历右子树。

 //中序遍历
    public void inorderTraversal(Node root){
        if (root == null){
            return;
        }
        Node node = root;
        while (node != null){
            if (node.leftChildTree == null){
                System.out.println("node = [" + node.data + "]");
                node = node.rightChildTree;

            }else {
                Node temp = node.leftChildTree;
                while (temp.rightChildTree != null && temp.rightChildTree != temp){
                    temp = temp.rightChildTree;
                }
                if (temp.rightChildTree == null){
                    temp.rightChildTree = node;
                    node = node.leftChildTree;
                }else{
                    temp.rightChildTree = null;
                    System.out.println("node = [" + node.data + "]");
                    node = node.rightChildTree;
                }
            }

        }
    }

解决了这道题,我们再扩展一下,看一下一个二叉树结构都应该有哪些功能呢?

基本操作:树的主要操作有
(1)创建树IntTree(&T)
(2)销毁树DestroyTree(&T)
(3)构造树CreatTree(&T,deinition)
(4)置空树ClearTree(&T)
(5)判空树TreeEmpty(T)
(6)求树的深度TreeDepth(T)
(7)获得树根Root(T)
(8)获取结点Value(T,cur_e,&e),将树中结点cur_e存入e单元中。
(9)数据赋值Assign(T,cur_e,value),将结点value,赋值于树T的结点cur_e中。
(10)获得双亲Parent(T,cur_e),返回树T中结点cur_e的双亲结点。
(11)获得最左孩子LeftChild(T,cur_e),返回树T中结点cur_e的最左孩子。
(12)获得右兄弟RightSibling(T,cur_e),返回树T中结点cur_e的右兄弟。
(13)插入子树InsertChild(&T,&p,i,c),将树c插入到树T中p指向结点的第i个子树之前。
(14)删除子树DeleteChild(&T,&p,i),删除树T中p指向结点的第i个子树。
(15)遍历树TraverseTree(T,visit())

原文地址:https://www.cnblogs.com/syd-fish-cat/p/9265521.html

时间: 2024-11-04 13:52:11

遍历二叉树的三种方法的相关文章

遍历Map的三种方法

Map<String,Object> map = new HashMap<>();map.put("1",1);map.put("2",2);map.put("3",3);// 第一种遍历,根据keySet()方法System.out.println("第一种遍历方法:");for(String key : map.keySet()) { Object obj = map.get(key); Syste

C#中遍历ArrayList的三种方法

using System; using System.Collections; using System.Linq; using System.Text; namespace ArrayListDemo { class Program { static void Main(string[] args) { ArrayList arr = new ArrayList(); arr.Add("How"); arr.Add("are"); arr.Add("yo

遍历集合的三种方法

List<String> list = new ArrayList<String>();list.add("aaa");list.add("bbb");list.add("ccc");方法一:超级for循环遍历for(String attribute : list) { System.out.println(attribute);}方法二:对于ArrayList来说速度比较快, 用for循环, 以size为条件遍历:for

层序遍历二叉树的两种方法

第一种也是最常用的一种,使用queue.还有一种不使用queue的方法.不使用queue的思路,其实就是每次都只存储一层的节点,然后遍历这一层的节点,是真正的按层遍历的思想.每次遍历的都是当前层,记录的都是当前层的下一层. public class test { public static void main(String[] args) { TreeNode root = new TreeNode(1); TreeNode r1 = new TreeNode(2); TreeNode r2 =

遍历List的三种方法

List<String> li = new ArrayList<String>(); li.add("1"); li.add("2"); li.add("3"); li.add("4"); //1.for //优点:效率最高,遍历快,可以根据自定计数器操作元素 //缺点:不适用所有集合,每次都需要在应用程序中手动强转和额外的获得list.size,还有一个缺点就是遍历过程中不允许删除元素 for (in

创建二叉树的两种方法以及三种遍历方法

二叉树的两种创建方法和三种遍历方法 这里的两种创建方法,一种值得是 数据结构上面的创建方法: 方法一 代码如下: 二叉树的结构定义如下: typedef struct BinaryTreeNode{ char value; struct BinaryTreeNode *left; struct BinaryTreeNode *right; }; - c语言版 void CreateBinaryTree(BinaryTreeNode **T) { char data; scanf("%d"

二叉树遍历的三种方法(以中序为例)

二叉树遍历的三种方法 递归 简单 时间O(n) 空间O(n) 非递归+栈 中等 时间O(n) 空间O(n) 非递归.不用栈 中等 时间O(n) 空间O(1) 伪代码实现--近C++代码 方法一:递归 1 Inorder-Tree-Walk(x) 2 if(x != NULL) 3 Inorder-Tree-Walk(x->left) 4 print x->key 5 Inorder-Tree-Walk(x->right) 方法二:非递归+栈 1 Inorder-Tree-Walk(x)

公交车站捡垃圾之二叉树的三种遍历方法

# 二叉树的遍历 今天下午看了二叉树的三种遍历方式,虽然能写出代码,但是理解可能不太到位,感觉很容易忘,所以想到一个形象的方法,把每个节点当作公交车站,而访问节点则是在这个公交车站捡垃圾,右子树和左子树则表示岔路.然后这个捡垃圾的人钟爱左边这个方向,所以一直以左优先.甲乙丙三个人,都爱捡垃圾,但是思考方式不同,所以捡垃圾的方法有点不同. 先序遍历 先序遍历最简单,秉承的原则是,甲很小心谨慎,每次经过公交车站,怕别人捡了,都把垃圾先捡到手,直到左边的路走完了,再往回走,但是回来的过程中,在公交车站

二叉树的三种递归遍历实现

声明:学过二叉树的童鞋可以跳过前面的故事,直接看最后的代码实现.  你见过二叉树吗?一种很神奇的树,传说见到他的人都是幸运的.如果你没见过,好运立马降临: 怎么样?有被惊艳到吗?好运已经送到,祝你今晚睡得香甜. 好了,送完祝福,下面讲一个神奇的故事: 讲故事前,简单说说二叉树. 那么我要说的二叉树是什么呢?它是一种数据结构,数据结构是什么可以自行百度一下,这里不讨论他.举一个现实中的例子:把某个家庭看作一棵树,这家的爸爸(妈妈)有两个孩子,那么爸爸(妈妈)就是树的根,俩孩子就是这棵树的叶子,而此