【非递归】实现二叉树的前序、中序、后续、层次遍历

先上代码,看不懂请看后面的图解就一定能懂了

创建Node类 :

package Tree1;

public class Node {
    //节点值
    int data;
    Node leftChild;	//左孩子
    Node rightChild ;	//右孩子

    //初始化,无参构造器
    public Node() {
        data = 0;
        leftChild = rightChild  = null;
    }
    //初始化,一参构造函数
    public Node(int value) {
        this.data = value;
        leftChild = rightChild  = null;
    }
}

方法实现类:

package Tree1;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Tree {
    /**
     * 非递归实现树先序,中序,后序递归(栈)
     */
        public static void main(String[] args) {
            Node node4 = new Node(4);
            Node node1 = new Node(1);
            Node node2 = new Node(2);
            Node node3 = new Node(3);
            Node node5 = new Node(5);
            Node node6 = new Node(6);
            Node node7 = new Node(7);
            node4.leftChild = node2;
            node4.rightChild = node6;
            node2.leftChild = node1;
            node2.rightChild = node3;
            node6.leftChild = node5;
            node6.rightChild = node7;
            System.out.println("=====先序遍历=====");
            preOrder(node4);

            System.out.println("\n=====中序遍历=====");
            midOrder(node4);

            System.out.println("\n=====后序遍历=====");
            latOrder(node4);

            System.out.println("\n=====层序遍历=====");
            floOrder(node4);

        }


        /**
         * 先序遍历
         *     1.先将根节点入栈
         *     2.访问根节点
         *     3.如果根节点存在右孩子,则将右孩子入栈
         *     4.如果根节点存在左孩子,则将左孩子入栈(注意:一定是右孩子先入栈,然后左孩子入栈)
         *     5.重复2-4
         * @param root
         */
        //传入根节点
        public static void preOrder(Node root){
            if (root==null){
                System.out.println("空树");
            }
            //创建栈
            Stack<Node> stack = new Stack<>();
            //进栈
            stack.push(root);
            //判断是否栈是否为空
            while(!stack.isEmpty()){
                //栈顶元素节点赋给temp
                Node temp = stack.pop();
                //输出节点
                System.out.printf(temp.data+" ");
                //判断左孩子是否为空
                if (temp.rightChild!=null){
                    //不为空就进栈
                    stack.push(temp.rightChild);
                }
                判断右孩子是否为空
                if (temp.leftChild!=null){
                    //不为空就进栈
                    stack.push(temp.leftChild);
                }

            }
        }

        /**
         * 中序遍历
         *     1.先将根节点入栈
         *     2.将当前节点的所有左孩子入栈,直到左孩子为空
         *     3.访问栈顶元素,如果栈顶元素存在右孩子,则继续第2步
         *     4.重复第2、3步,直到栈为空并且所有的节点都被访问
         * @param root
         */
        public static void midOrder(Node root){
            if (root==null){
                System.out.println("空树");
            }
            Node temp = root;
            Stack<Node> stack = new Stack<>();
            while(temp!=null || !stack.isEmpty()){

                while(temp!=null){
                    stack.push(temp);
                    temp = temp.leftChild;

                }
                temp = stack.pop();
                System.out.printf(temp.data+" ");
                if(temp.rightChild!=null){
                    temp = temp.rightChild;
                }else {
                    temp = null;
                }
            }

        }

        /**
         * 后续遍历
         *     1.根节点入栈
         *     2.将根节点的左子树入栈,直到最左,没有左孩子为止
         *     3.得到栈顶元素的值,先不访问,判断栈顶元素是否存在右孩子,如果存在并且没有被访问,
         *       则将右孩子入栈,否则,
         *       就访问栈顶元素
         * @param root
         */
        public static void latOrder(Node root){
            if (root==null){
                System.out.println("空树");
            }
            Node temp = root;
            Node pre = null;
            Stack<Node> stack = new Stack<>();
            while(temp!=null || !stack.isEmpty()){
                while(temp!=null){
                    stack.push(temp);
                    temp = temp.leftChild;
                }
                if(!stack.isEmpty()){
                    temp = stack.peek();
                    if(temp != null){
                        if(temp.rightChild == null || temp.rightChild == pre){
                            temp = stack.pop();
                            System.out.printf(temp.data+" ");
                            pre = temp;
                            temp = null;
                        }else {
                            temp = temp.rightChild;
                        }
                    }
                }

            }
        }

        /**
         * 层序遍历
         * @param root
         */
        public static void floOrder(Node root){
            if (root==null){
                System.out.println("空树");
            }
            Queue<Node> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()){
                Node temp = queue.poll();
                System.out.printf(temp.data+" ");
                if (temp.leftChild!=null){
                    queue.offer(temp.leftChild);
                }
                if (temp.rightChild!=null){
                    queue.offer(temp.rightChild);
                }
            }
        }

}

非递归实现前序遍历

前序遍历的顺序:根---左---右

对于非递归实现二叉树的前序遍历得借助栈这一数据结构,具体做法如下:

1. 创建一个栈,并将二叉树的根节点保存在栈中

2. 当栈不为空的时候,将栈顶元素取出遍历

3. 如果根结点有右子树,将右子树的根节点保存在栈中

4. 再遍历根的左子树,而左子树遍历的顺序也是先遍历根,看是否有右子树,再继续遍历左子树,按照这个顺序进行循环

5. 最后当栈取到空的时候返回

非递归实现中续遍历

中序遍历的顺序:左---根---右

实现非递归遍历借助栈这一数据结构,具体做法如下:

1. 依次将根与左子树的根节点入栈

2. 取出栈顶元素遍历

3. 访问栈顶元素的右子树

4. 栈顶元素右子树也是二叉树,所以将上述操作进行循环

非递归实现后续遍历

后续遍历顺序:左---右---根

实现非递归后续遍历也得借助栈这一数据结构,具体做法如下:

1. 第一步与中序遍历的操作相同,依次将左子树的根节点保存在栈中

2. 获取栈顶元素,如果该结点的右子树为空,则遍历该结点,否则遍历该结点的右子树

3. 右子树又是一颗二叉树,继续循环上述操作

注意:用pre标记每一次遍历的元素,这里每一次获取栈顶元素,当获取栈顶元素的右为空时或者等于标记的结点时,此时都遍历该元素,这样做目的是防止循环,导致栈溢出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值