代码改变世界

数据结构与算法回顾之二叉树的遍历(下)

2010-12-13 13:46  yearN  阅读(1637)  评论(2编辑  收藏  举报

上节我们给出了广度优先遍历算法的实现和深度优先遍历算法的递归实现,本节我们讨论深度优先的三种遍历形式的非递归实现。

1.非递归先序遍历:先访问树的根节点,然后是左子树和右子树。根节点入栈,循环判断栈是否为空,如果不为空,出栈跟节点并访问根节点,如果右子树非空,让右子树先入栈;如果左子树非空,再让左子树入栈,执行循环,直到栈中为空。

代码如下:

 	/// <summary>
        /// 先序遍历
        /// </summary>
        /// <param name="root">开始节点</param>
        public void IterativePreorder(BSTNode root)
        {
            BSTNode p = root;
            Stack<BSTNode> travStack = new Stack<BSTNode>();
            if (p != null)
            {
                travStack.Push(p);
                while (!travStack.IsEmpty())
                {
                    p = travStack.Pop();
                    BST.Visit(p);
                    if (p.Right != null)
                    {
                        travStack.Push(p.Right);
                    }
                    if (p.Left != null)             //左子树入栈在
                    {                               //右子树之后
                        travStack.Push(p.Left);
                    }
                }
            }
        }

2.非递归后序遍历:要遍历树的根节点,后序遍历要求在遍历完左右子树后,再访问根。需要判断根结点的左右子树是否均遍历过。在访问左子树之前和访问右子树之前都有记录下根节点,所以可以用一个辅助的引用q来区分知网两种情况。

代码如下:

 	/// <summary>
        /// 后序遍历
        /// </summary>
        /// <param name="root">开始节点</param>
        public void IterativePostorder(BSTNode root)
        {
            BSTNode p = root;
            BSTNode q = root;
            Stack<BSTNode> travStack = new Stack<BSTNode>();
            while (p != null)
            {
                for (; p.Left != null; p = p.Left)
                {
                    travStack.Push(p);
                }
                while (p != null && (p.Right == null || p.Right == q))
                {
                    BST.Visit(p);
                    q = p;
                    if (travStack.IsEmpty())
                    {
                        return;
                    }
                    p = travStack.Pop();
                }
                travStack.Push(p);
                p = p.Right;
            }
        }

注意只有一个子孙的节点只能被压入一次,且树叶则根本不需要压入。

3.非递归中序遍历:要遍历树的根节点,中序遍历要求在遍历完左子树后,访问根,再遍历右子树。所以访问左子树前先将右子树入栈,再将根节点入栈,直到左子树为空。再利用出栈操作来访问根节点和右子树。

代码如下:

 	/// <summary>
        /// 中序遍历
        /// </summary>
        /// <param name="root">开始节点</param>
        public void IterativeInorder(BSTNode root)
        {
            BSTNode p = root;
            Stack<BSTNode> travStack = new Stack<BSTNode>();
            while (p != null)
            {
                //节点自身和右孩子入栈,然后前进到左孩子
                while (p != null)
                {
                    if (p.Right != null)
                    {
                        travStack.Push(p.Right);
                    }
                    travStack.Push(p);
                    p = p.Left;
                }

                p = travStack.Pop();//出栈一个节点,这个节点没有左孩子

                //访问没有右孩子的节点
                while (!travStack.IsEmpty() && p.Right == null)
                {
                    BST.Visit(p);
                    p = travStack.Pop();
                }

                //访问含有右孩子的节点
                BST.Visit(p);
                if (!travStack.IsEmpty())
                {
                    p = travStack.Pop();
                }
                else
                {
                    p = null;
                }
            }
        }