public void preOrderTravNoRecur(Node n) {
Stack<Node> stack = new Stack<Node>();
stack.add(root);
while (!stack.empty()) {
Node t = stack.pop();
System.out.print(t.value + " ");
if (t.rightNode != null)
stack.add(t.rightNode);
if (t.leftNode != null)
stack.add(t.leftNode);
}
}
2.第二种实现方式更普遍(中序遍历的非递归使用了同样的思路):
初始:维护一个栈 S 和一个节点变量 N。节点变量赋值为根节点。
循环:将节点变量 N 的左儿子循环的输出,并推入栈 S 中,直到没有左儿子;推出栈 S 的顶节点,节点变量 N 赋值为栈 S 顶节点的右节点。
分析:不同于递归调用的思路。栈 S 用于实现对某节点的左边支递归值的存储,以便回溯;节点变量 N 则用于遍历某节点的右边枝(这些节点是从栈 S 顶读出的节点,依次做处理),由于右边枝是最后才会被访问到的,故在处理右边枝的时候,不需要存储右边枝的信息,依次处理即可。
1234567891011121314
public void preOrderTravNoRecurII(Node n) {
System.out.println("No Recursive: ");
Stack<Node> s = new Stack<Node>();
while (n != null | !s.empty()){
while (n!=null ){
System.out.print(n.value + " ");
s.add(n);
n = n.leftNode;
}
n = s.pop();
n = n.rightNode;
}
System.out.println();
}
中序遍历
递归实现
1234567
public void inorderTrav(Node n) {
if (n != null) {
inorderTrav(n.leftNode);
System.out.print(n.value + " ");
inorderTrav(n.rightNode);
}
}
非递归实现
初始:维护一个栈 S 和一个节点变量 N。节点变量赋值为根节点。
循环:将节点变量 N 的左儿子循环的输出,并推入栈 S 中,直到没有左儿子;节点变量 N 赋值为栈 S 顶节点的右节点。
public void inorderTravNoRecu(Node n) {
System.out.println("No Recursive: ");
Stack<Node> s = new Stack<Node>();
while (n != null | !s.empty()){
while (n!=null ){
s.add(n);
n = n.leftNode;
}
n = s.pop();
System.out.print(n.value + " ");
n = n.rightNode;
}
}
后序遍历
递归实现
123456789101112131415
public void preOrderTravNoRecurII(Node n) {
System.out.println("No Recursive: ");
Stack<Node> s = new Stack<Node>();
while (n != null | !s.empty()){
while (n!=null ){
System.out.print(n.value + " ");
s.add(n);
n = n.leftNode;
}
n = s.pop();
n = n.rightNode;
}
System.out.println();
}
非递归实现
初始:1.维护一个栈 S、一个节点变量 N 和一个标记数组。节点变量赋值为根节点,栈暂时存储便利到的节点,标记数组用于标记栈中的节点是否已经访问过右边节点。2.将根节点的所有左儿子压入栈中。
public void postOrderTravNoRecu(Node n) {
Stack<Node> stack = new Stack<Node>();
int[] flag = new int[max];
while (n != null) {
stack.push(n);
flag[stack.size()] = 0;
n = n.leftNode;
}
while (!stack.empty()) {
n = stack.peek();
while(n.rightNode != null && flag[stack.size()] == 0) {
n = n.rightNode;
flag[stack.size()] = 1;
while (n != null) {
stack.push(n);
flag[stack.size()] = 0;
n = n.leftNode;
}
n = stack.peek();//TODO be careful about this
}
n = stack.pop();
System.out.print(n.value + " ");
}
}
层序遍历
无法使用递归方法
层序遍历不同于其他的遍历。可以通过反证法证明:
如果能实现对 A 节点的层序递归,在对 A 节点处理的过程中,应该递归的对两个儿子 B 和 C 分别调用了层序遍历。在这种情况下,我们无法让 B 和 C 的同一个层级的儿子在集中的时间中被遍历到,换言之,B 的第一层儿子在对 B 的调用中被遍历,而 C 的第一层儿子,则在对 C 的调用中遍历,这是分离开的。不成立,得证。
非递归方法:
分析:此方法类似于前序遍历的非递归方法的第一种。用一个队列维护信息。
123456789101112131415
public void levelOrderTrav(Node n) {
System.out.print("Level OrderTrav: ");
Queue<Node> q = new LinkedList<Node>();
q.add(n);
while (q.size() != 0) {
n = q.poll();
System.out.print(" " + n.value);
if (n.leftNode != null)
q.add(n.leftNode);
if (n.rightNode != null)
q.add(n.rightNode);
}
}