二叉树的非递归遍历

来源:互联网 发布:淘宝怎么去推广 编辑:程序博客网 时间:2024/06/08 09:01

二叉树节点:

public class Node{public int data = 0;public Node lchild = null;public Node rchild = null;}

前序遍历

List<Node> PreorderTraverse(Node root){List<Node> nodes = new List<Node>();if (root == null){return nodes;}Stack<Node> stack = new Stack<Node>();stack.Push(root);while (stack.Count > 0){Node node = stack.Pop();nodes.Add(node);if (node.rchild != null){stack.Push(node.rchild);}if (node.lchild != null){stack.Push(node.lchild);}}return nodes;}

前序遍历非常简单,先把根节点压入栈中,然后每从栈里取一个节点,就把它的两个子节点放入栈中,这样循环直到栈空即可。


中序遍历

List<Node> InorderTraverse(Node root){List<Node> nodes = new List<Node>();if (root == null){return nodes;}Node node = root;Stack<Node> stack = new Stack<Node>();while (node != null || stack.Count > 0){if (node != null) // 状况1{stack.Push(node);node = node.lchild; // node变为状况1或3的节点}else // 状况3{node = stack.Pop(); // node变为状况2的节点nodes.Add(node);node = node1.rchild; // node变为状况1或3的节点}}return nodes;}

中序遍历稍微麻烦点,因为我们每次拿到手的节点有三种状况:

1. 它是一个尚未遍历的子树的根节点,其左子树还没处理,所以我们要把它入栈,然后处理它的左子节点,继续状况1或3。

2. 它是左子树遍历完成后的从栈取出的父节点,它的左子树已经处理完毕,只要把它输出然后就可以忽略它了,然后处理它的右子节点,回到状况1或3。

3. 它是空的,直接从栈中取新的节点,回到状况2。


后序遍历

List<Node> PostorderTraverse(Node root){List<Node> nodes = new List<Node>();if (root == null){return nodes;}Stack<Node> stack = new Stack<Node>();stack.Push(root);Node pnode = null;while (stack.Count > 0){Node node = stack.Peek();// 如果pnode不是node的左/右子节点,表明node节点是以左/右子节点身份入栈的,那么以它为根的子树尚未遍历,需要把它的左右子节点入栈if (pnode == null || (pnode != node.lchild && pnode != node.rchild)){if (node.rchild != null){stack.Push(node.rchild);}if (node.lchild != null){stack.Push(node.lchild);}}// 如果它还是栈顶(没有子节点入栈),那么它一定是没有子节点或者是处理完子节点后退回到它if (stack.Peek() == node){nodes.Add(node);stack.Pop();pnode = node;}}return nodes;}

    后续遍历是最复杂的,主要是从栈中取出节点node的时候,node有多种情况(前序和中序里的栈顶节点都是直接输出并抛弃,省心)

    先看每个节点入栈时的状况:

1. 它是以子树的根节点的身份入栈的,一定同时还会把它的右子节点(状况2)和左子节点(状况3)入栈并压在它上面,当轮到它出栈时,它的左右子节点一定已先出栈并处理过了,此时我们直接输出它,代表以它为根的子树已经全部处理完毕

2. 它是以一个右子节点身份入栈的,那么轮到它出栈的时候,它是一颗尚未处理的子树的根节点,所以需要重新入栈进入状况1

3. 它是以一个左子节点身份入栈的,处理方法同2

    问题是当我们如何才能得知从栈顶弹出的node是状况1还是状况23下入栈的呢?这得看我们最近一次输出的节点pnode跟它的关系了:

1 如果pnode是node的子节点,则node一定是以状况1入栈的,如果是状况2/3,它的子节点都没入过栈,更不可能输出过。所以按照状态1直接输出node就好了

2 如果pnode跟node无关,则按状况2/3处理

3 如果pnode跟node无关,且node本身是叶节点,我们也把按照状态1直接输出它



中序遍历
中序遍历
0 0
原创粉丝点击