万金流
以码会友。 吾Q:578751655。 水平有限,轻喷,谢!

如题。

二叉树类代码的基础上,三序遍历JAVA代码如下:

// 递归遍历很简单。
    // 跟着下面的,另外两个也很容易写。
    public void front()// 递归-前序遍历
    {
        System.out.print(v + "\t");
        if (left != null)
        {
            left.front();
        }
        if (right != null)
        {
            right.front();
        }
    }

    // 中序后序,验证用。。。。。。。。。。。。。。。开始
    public void mid()
    {
        if (left != null)
        {
            left.mid();
        }
        System.out.print(v + "\t");
        if (right != null)
        {
            right.mid();
        }
    }

    public void back()
    {
        if (left != null)
        {
            left.back();
        }
        if (right != null)
        {
            right.back();
        }
        System.out.print(v + "\t");
    }
    // 中序后序,验证用。。。。。。。。。。。。。。。结束

    // 栈式前序遍历相对简单,每一轮压栈完成,栈顶都是可输出的节点,输出即可。
    // 对于后续有子节点的节点,拆散了按“右左根”的顺序(即先序遍历的反序)压栈。
    // 中序和后序就不太好写了。
    public void front_Stack()// 栈-前序遍历
    {
        Stack<MyBinaryNode> stack_treenode = new Stack<MyBinaryNode>();
        MyBinaryNode t;
        stack_treenode.push(this);
        while (!stack_treenode.empty())
        {
            t = stack_treenode.pop();
            if (t.right != null)
            {
                stack_treenode.push(t.right);
            }
            if (t.left != null)
            {
                stack_treenode.push(t.left);
            }
            System.out.print(t.v + "\t");
        }
    }

    // 中序
    // 判断栈内节点是否是可输出的节点,需要对比它后一个节点是不是它的右节点。
    // (为什么不跟它前面的节点比较?因为它前面的节点会在操作中被打乱,无法直接判断)
    // 但考虑到某根节点的右子树为空,则无法确定它的左子树是否已经入栈(如根节点右子树为空,左子树已全部入栈;不是根节点,则未入栈)。
    //也就无法确定该点应该输出或压栈。
  //所以,上述想法仅对于满二叉树有效。
//一种思路: //在某子树分“右根左”三部分入栈的时候,如果考虑把根节点的左右指针全部打断,它也就变相成了一个“能够输出”的标记。 public void middle_Stack() { Stack<MyBinaryNode> stack_treenode = new Stack<MyBinaryNode>(); MyBinaryNode t; stack_treenode.push(this); while (!stack_treenode.empty()) { t = stack_treenode.pop(); if (t.right == null && t.left == null)/* 它可输出 */ { System.out.print(t.v + "\t"); } else { if (t.right != null) { stack_treenode.push(t.right); } stack_treenode.push(t); if (t.left != null) { stack_treenode.push(t.left); } t.left=t.right=null;/*再弹出这个节点的时候就可以输出了*/ } } } //后序遍历思想类似 public void back_Stack() { Stack<MyBinaryNode> stack_treenode = new Stack<MyBinaryNode>(); MyBinaryNode t; stack_treenode.push(this); while (!stack_treenode.empty()) { t = stack_treenode.pop(); if (t.right == null && t.left == null)/* 它可输出 */ { System.out.print(t.v + "\t"); } else { stack_treenode.push(t); if (t.right != null) { stack_treenode.push(t.right); } if (t.left != null) { stack_treenode.push(t.left); } t.left=t.right=null;/*再弹出这个节点的时候就可以输出了*/ } } }

这样做会带来问题,以下用C#进行说明和演示:

//可这样操作会破坏树结构。
        //验证:运行mid_Stack()之后运行back_Stack()。
        //解决这个问题,可以为这个树结构的每个节点引入一个标志位,来说明这个节点是否可以输出。
        //也可以用另一个栈来专门存储状态,和这个栈同进同出。

        //中序
        public void middle_Stack1()
        {
            Stack<MyBinaryNode> stack_treenode = new Stack<MyBinaryNode>();
            //本栈存放对应节点的状态(T/F),表示它是否应直接输出。
            Stack<bool> stack_status = new Stack<bool>();
            MyBinaryNode t;
            bool status;
            stack_treenode.Push(this);
            stack_status.Push(false);
            while (!(stack_treenode.Count == 0))
            {
                t = stack_treenode.Pop();
                status = stack_status.Pop();
                if (t.right == null && t.left == null||status==true)/* 它可输出 */
                {
                    Console.Write(t.v + "\t");
                }
                else
                {
                    if (t.right != null)
                    {
                        stack_treenode.Push(t.right);
                        stack_status.Push(false);
                    }
                    stack_treenode.Push(t);
                    stack_status.Push(true);
                    if (t.left != null)
                    {
                        stack_treenode.Push(t.left);
                        stack_status.Push(false);
                    }
                }
            }
        }
        //后序
        public void back_Stack1()
        {
            Stack<MyBinaryNode> stack_treenode = new Stack<MyBinaryNode>();
            //本栈存放对应节点的状态(T/F),表示它是否应直接输出。
            Stack<bool> stack_status = new Stack<bool>();
            MyBinaryNode t;
            bool status;
            stack_treenode.Push(this);
            stack_status.Push(false);
            while (!(stack_treenode.Count == 0))
            {
                t = stack_treenode.Pop();
                status = stack_status.Pop();
                if (t.right == null && t.left == null || status == true)/* 它可输出 */
                {
                    Console.Write(t.v + "\t");
                }
                else
                {
                    stack_treenode.Push(t);
                    stack_status.Push(true);
                    if (t.right != null)
                    {
                        stack_treenode.Push(t.right);
                        stack_status.Push(false);
                    }
                    if (t.left != null)
                    {
                        stack_treenode.Push(t.left);
                        stack_status.Push(false);
                    }
                }
            }
        }

前序遍历道理类似。

在树节点中使用标志位道理也类似。

大家可以自行完成。


 层序遍历,借助队列很容易完成,此处略。

 

posted on 2020-11-20 11:36  万金流  阅读(210)  评论(0)    收藏  举报