在面试的时候,我们会经常被问到树的三种遍历,也就是前序遍历、中序遍历和后序遍历。
所谓前序遍历,就是先访问根节点,再左,再右。命名方式就是根据根节点是在哪访问的去定义的。下面我们先用Java实现三种遍历的递归,是非常的简单。
树的前序遍历:
public void recursiveProOrder(Node root) {
if (root != null) {
System.out.print(root.value);
if (root.left != null) {
recursivePostOrder(root.left);
}
if (root.right != null) {
recursivePostOrder(root.right);
}
}
}
树的中序遍历:
public void recursiveInOrder(Node root) {
if (root != null) {
if (root.left != null) {
recursiveInOrder(root.left);
}
System.out.print(root.value);
if (root.right != null) {
recursiveInOrder(root.right);
}
}
}
树的后序遍历:
public void recursivePostOrder(Node root) {
if (root != null) {
if (root.left != null) {
recursivePostOrder(root.left);
}
if (root.right != null) {
recursivePostOrder(root.right);
}
System.out.print(root.value);
}
}
下面介绍如何用非递归的方式进行遍历。所谓递归,其实在语言的底层层面上来讲,也是用栈来实现的,因此,要把递归的算法改为非递归,我们都可以考虑用栈来实现怎么操作。其中,前序和中序的非递归实现都比较容易,需要重点理解的是树的后序遍历的非递归实现。下面直接给出代码。
树的前序遍历(非递归):
public void preOrder(Node node)
{
Stack<Node> stack = new Stack<>();
while(node != null || !stack.empty())
{
while(node != null)
{
System.out.print(node.element + " ");
stack.push(node);
node = node.left;
} //while循环负责扫描所有当前结点,并判断有没有左子树
if(!stack.empty()) //当stack为空的时候,说明没有左子树了
{
node = stack.pop();
node = node.right;
}
}
}
树的中序遍历(非递归):
public void midOrder1(Node node)
{
Stack<Node> stack = new Stack<>();
while(node != null || !stack.empty())
{
while (node != null)
{
stack.push(node);
node = node.left;
} //先压到树的最左下角的左子树
if(!stack.empty())
{
node = stack.pop();
System.out.print(node.element + " ");
node = node.right;
}
}
}
树的后序遍历(非递归):
public void postOrder(Node node){
if(node==null)
return;
Stack<Node> s = new Stack<Node>();
Node curNode; //当前访问的结点
Node lastVisitNode; //上次访问的结点
curNode = node;
lastVisitNode = null;
//把currentNode移到左子树的最下边
while(curNode!=null){
s.push(curNode);
curNode = curNode.getLchild();
}
while(!s.empty()){
curNode = s.pop(); //弹出栈顶元素
//一个根节点被访问的前提是:无右子树或右子树已被访问过
if(curNode.getRchild() != null
&& curNode.getRchild() != lastVisitNode){
//根节点再次入栈
s.push(curNode);
//进入右子树,且可肯定右子树一定不为空
curNode = curNode.getRchild();
while(curNode != null){
//再走到右子树的最左边
s.push(curNode);
curNode = curNode.getLchild();
}
}else{
//访问
System.out.println(curNode.getData());
//修改最近被访问的节点
lastVisitNode = curNode;
}
} //while
}
对于后序遍历的非递归实现,需要好好理解。