如题。
在二叉树类代码的基础上,三序遍历JAVA代码如下:
// 递归遍历很简单。 // 跟着下面的,另外两个也很容易写。 public void front()// 递归-前序遍历 { System.out.print(v + " "); if (left != null) { left.front(); } if (right != null) { right.front(); } } // 中序后序,验证用。。。。。。。。。。。。。。。开始 public void mid() { if (left != null) { left.mid(); } System.out.print(v + " "); if (right != null) { right.mid(); } } public void back() { if (left != null) { left.back(); } if (right != null) { right.back(); } System.out.print(v + " "); } // 中序后序,验证用。。。。。。。。。。。。。。。结束 // 栈式前序遍历相对简单,每一轮压栈完成,栈顶都是可输出的节点,输出即可。 // 对于后续有子节点的节点,拆散了按“右左根”的顺序(即先序遍历的反序)压栈。 // 中序和后序就不太好写了。 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 + " "); } } // 中序 // 判断栈内节点是否是可输出的节点,需要对比它后一个节点是不是它的右节点。 // (为什么不跟它前面的节点比较?因为它前面的节点会在操作中被打乱,无法直接判断) // 但考虑到某根节点的右子树为空,则无法确定它的左子树是否已经入栈(如根节点右子树为空,左子树已全部入栈;不是根节点,则未入栈)。 //也就无法确定该点应该输出或压栈。
//所以,上述想法仅对于满二叉树有效。 //一种思路: //在某子树分“右根左”三部分入栈的时候,如果考虑把根节点的左右指针全部打断,它也就变相成了一个“能够输出”的标记。 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 + " "); } 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 + " "); } 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 + " "); } 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 + " "); } 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); } } } }
前序遍历道理类似。
在树节点中使用标志位道理也类似。
大家可以自行完成。
层序遍历,借助队列很容易完成,此处略。