二叉树前序,后续,中序遍历 非递归

前序

根左右
需要先压入根,取出,然后依次压入 右节点 ,左节点,再取出。。

package testjvm;
/**
 * @Classname 二叉树
 * @Description TODO
 * @Date 2021/3/13 20:43
 * @Created by wangxutao
 */

import java.util.*;

class tree_Node{
//定义 节点
    public tree_Node() {
    }
    int value;
    tree_Node left=null;
    tree_Node right = null;

    public tree_Node(int value, tree_Node left, tree_Node right) {
        this.value = value;
        this.left = left;
        this.right = right;
    }

    public tree_Node(int value) {
        this.value = value;
    }
}

public class 二叉树 {
    //前序遍历,先压入右边,因为先弹出 左边
    public static void main(String[] args) {
    //测试
        二叉树 er = new 二叉树();
        tree_Node n=new tree_Node(100);
        n.left=new tree_Node(90);
        n.right=new tree_Node(80);
        n.left.left = new tree_Node(70);
        n.left.right = new tree_Node(60);
        er.preOrder(n);

    }

    void preOrder(tree_Node root) {
        Stack<tree_Node> stack = new Stack<>();
        if (root != null) {
            stack.push(root); //压入根
        }
        while (!stack.isEmpty()) {
            root = stack.pop();
            visit(root);
            if (root.right != null) {
                stack.push(root.right);
            }
            if (root.left != null) {
                stack.push(root.left);
            }
        }
    }
    void visit(tree_Node tree_Node) {
        System.out.println(tree_Node.value);
    }
    

    //后续遍历  那么可以把后序当作:根->右->左,然后再反转一下即可。
//    申请两个栈s1、s2,先将头节点入栈s1。从s1中弹出栈顶节点记为cur,然后依次将cur的左孩子和右孩子压入s1。
//    在这过程中每一个从s1中弹出的节点均压入s2。当s1为空后,从s2中依次弹出的节点便是后序遍历的次序。
//    主要就是利用两个栈来进行“倒腾“,压入s2的顺序为中、右、左,弹出的顺序就变成了左、右、中。
    void postOrder(tree_Node tree_Node) {

    }
}

中序

令cur等于head步骤1:先把cur入栈,然后不停让cur=cur->left,重复此步骤。即把cur下的所有左孩子节点入栈。直到cur为空。步骤2:从栈中弹出栈顶给cur,打印该节点,然后令cur=cur->right,回到步骤2。步骤3:当栈为空时且cur为空时,过程结束。入栈的顺序可参考下图:

 void middleOrder(Node node) {
        if (node == null) {
            return;
        }
        Node curnode =node;
        Stack<Node> stack = new Stack<>();
        while (!stack.isEmpty() || curnode!=null) {
            //所有左节点入栈
            while (curnode != null) {
                stack.push(curnode);
                curnode = curnode.left;
            }
            //弹出左节点,入栈右节点
            curnode = stack.pop();
            visit(curnode);
            // 弹出后,指向当前节点的右节点
            curnode=curnode.right;
        }
    }

后序

简单版(两个栈)
申请两个栈s1、s2,先将头节点入栈s1。从s1中弹出栈顶节点记为cur,然后依次将cur的左孩子和右孩子压入s1。在这过程中每一个从s1中弹出的节点均压入s2。当s1为空后,从s2中依次弹出的节点便是后序遍历的次序。
主要就是利用两个栈来进行“倒腾“,压入s2的顺序为中、右、左,弹出的顺序就变成了左、右、中。

 void postOrder(Node node) {
        if (node == null) {
            return;
        }
        Node curnode =node;
        Stack<Node> stack = new Stack<>();
        Stack<Node> stack2 = new Stack<>();
        stack.push(curnode);
        while (!stack.isEmpty()  ) {
            curnode = stack.pop();
            stack2.push(curnode);
            if (curnode.left != null) {
                stack.push(curnode.left);
            }
            if (curnode.right != null) {
                stack.push(curnode.right);
            }
        }
        while (!stack2.isEmpty()) {
            Node pop = stack2.pop();
            visit(pop);
        }
    }

申请一个栈,将头节点压入栈。
现在我们思考一下:当遍历到一个节点时,如何判断这次遍历是打印该点,还是先处理它的孩子呢?
有以下几种情况:

该节点的左右孩子皆为空,即该节点为叶子节点,那么这次遍历就是打印该点。
如果上一次打印的节点为该节点的右孩子,说明该节点的子树处理完毕,这次遍历就是打印该点。
如果上一次打印的节点为该节点的左孩子,且该节点的右孩子为空,说明该节点的子树处理完毕,这次遍历就是打印该点。
否则说明子树没有被访问过,按照右孩子、左孩子的顺序入栈。

void PosOrderUnRecur(Node* head)
{
	if (head)
	{
		stack<Node*> stack;
		stack.push(head);
		Node* last = nullptr;
		Node* top;
		while (!stack.empty())
		{
			top = stack.top();
			if ((top->left == nullptr && top->right == nullptr) || // 叶子节点
				(top->right == nullptr && last == top->left) || // 上个访问为左孩子,且右孩子为空
				last == top->right) // 上个访问为右孩子
			{
				cout << top->value << " ";
				last = top;
				stack.pop();
			}
			else
			{
				if (top->right)
					stack.push(top->right);
				if (top->left)
					stack.push(top->left);
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值