二叉树的先序 中序 后序遍历 非递归

本文详细介绍了如何使用栈非递归地实现二叉树的先序、中序和后序遍历。在先序遍历中,先访问根节点,然后将节点压栈并遍历左子树;中序遍历则是先遍历左子树,然后访问根节点并遍历右子树;后序遍历较为复杂,需要区分何时输出根节点何时访问右孩子,确保根节点在其右孩子之后访问。

二叉树的先序 中序 后序遍历 非递归实现

定义二叉树类

 public class BinaryTreeNode
 {
     public char? data;
     public BinaryTreeNode leftChild, rightChild;
 }

先序遍历

public void PreorderTraverse(BinaryTreeNode tree)
{
    Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
    BinaryTreeNode current = tree;

    while (current != null || stack.Count != 0)
    {
        if (current != null)
        {
            Console.Write(current.data + " ");
            stack.Push(current);
            current = current.leftChild;
        }
        else
        {
            current = stack.Pop().rightChild;
        }
    }
}

中序遍历

public void InderTraverse(BinaryTreeNode tree)
{
    Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
    BinaryTreeNode current = tree;

    while (current != null || stack.Count > 0)
    {
        if (current != null)
        {
            stack.Push(current);
            current = current.leftChild;
        }
        else
        {
            current = stack.Pop();
            Console.Write(current.data + " ");
            current = current.rightChild;
        }
    }
}

后序遍历
后序遍历比前两种遍历稍复杂一点,造成这个的原因是后序遍历根节点的访问在其右孩子之后。然而在遍历过程中又需要通过根节点去指向(获取)其右节点,此时也需要访问根节点但是不需要输出他。所以关键点就在于区分是要输出根节点还是访问其右孩子。
仔细观察后序遍历的过程就会发现,从左孩子过来时,下一步应该是访问右孩子而不是输出根节点。而如果是从右孩子过来,下一步就应该输出根节点了。

public void PostOrderTraverse(BinaryTreeNode tree)
{
    Stack<BinaryTreeNode> stack = new Stack<BinaryTreeNode>();
    BinaryTreeNode current = tree;

    while (current != null || stack.Count > 0)
    {
        if (current != null)
        {
            stack.Push(current);
            current = current.leftChild != null ? current.leftChild : current.rightChild;
        }
        // 1.右孩子为空了(执行到else 一定是右孩子为空,右孩子为空那根据三目表达式,左孩子也为空。也即是栈顶为叶子节点.)
        // 2.先打印这个节点,然后判断此节点是其父节点的左孩子还是右孩子。
        //  3.如果是右孩子,则current 指向右孩子。然后重复2(也即判断刚打印节点的父节点是其爷爷节点的右孩子还是左孩子)。
        //  4.如果是左孩子则 current 指向其父节点的右孩子,继续重复。
        else
        {
            current = stack.Pop();
            Console.Write(current.data + " ");

            // 如果当前节点是其父节点的右孩子,则打印父节点
            while (stack.Count > 0 && current != stack.Peek().leftChild)
            {
                current = stack.Pop();
                Console.Write(current.data + " ");
            }
            if (stack.Count == 0)
            {
                break;
            }
            // 如果当前节点是其父节点的左孩子, 则转到父节点的右孩子继续遍历
            if (current == stack.Peek().leftChild)
            {
                current = stack.Peek().rightChild;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值