二叉树在数据结构中是非常常用的,尤其是关于它的各种遍历算法,经常有关于递归和非递归的实现。下面来一一介绍各种遍历方式。
下面是先序遍历:
先序遍历:首先遍历根节点,然后再遍历左子树,再遍历右子树,那么如果采用递归来遍历,就是首先每一次先输出那个根节点的值,然后接着采用递归方式来遍历。代码如下:
class TreeNode
{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x)
{
val = x;
}
}
public void preOrder(TreeNode root)
{
if(root != null)
{
System.out.println(root.val);
if(root.left != null)
preOrder(root.left);
if(root.right != null)
preOrder(root.right);
}
}
如果考虑不采用递归来做,那么就是用Stack来实现。
因为栈有个先进后出的特点,所以在将节点入栈的时候,首先要考虑是先将右子树先入栈,然后再将左子树入栈,因为是出栈的顺序是先进后出,所以这里要特别当心。然后每一次栈顶的元素先出栈,然后顺带着将这个栈顶元素的右子树先入栈,然后是左子树再入栈,一定是这样的顺序。注意,栈底元素在还没出栈之前一定是右子树的根节点。直到第一次它出栈。
public class Solution
{
public ArrayList<Integer> preorderTraversal(TreeNode root)
<span style="font-family: Arial, Helvetica, sans-serif;"> {</span>
ArrayList<Integer> returnList = new ArrayList<Integer>();
if(root == null)
return returnList;
Stack<TreeNode> stack = new Stack<TreeNode>();
stack.push(root);
while(!stack.empty()){
TreeNode n = stack.pop(); //每次先让它出栈
returnList.add(n.val);
if(n.right != null){
stack.push(n.right);
}
if(n.left != null){
stack.push(n.left);
}
}
return returnList;
}
}
其次是中序遍历:
首先也是采用递归的方式,就是先遍历左子树,然后遍历根节点,接着遍历右子树。所以代码可以这样写:
class TreeNode
{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x)
{
val = x;
}
}
public void inOrder(TreeNode root)
{
if(root == null)
return;
else if(root != null)
{
if(root.left != null)
inOrder(root.left);
System.out.println(root.val);
if(root.right != null)
inOrder(root.right);
}
}
接下来就是采用非递归的方式来进行中序遍历。非递归来中序遍历一棵二叉树,采用的数据结构还是栈,首先,一直循环将左子树压入栈中,直到那个左子树节点为空,那么现在在栈中的所有节点都是关于左子树的,然后开始将栈中的头结点压出栈。然后看它有木有右子树,因为刚才的头结点肯定是没有左子树的节点,但是根据中序遍历的情况,有可能还有右子树,所以得考虑。然后如果有右子树,那么就将这个人右子树节点压入栈中,然后再次循环,看这个右子树节点是否有左子树,如果有,那么继续循环地压入,直到碰到没有左子树的情况,然后将头结点压出栈,接下来就是重复这样循环实现。其实和递归实现的原理差不多。
class TreeNode
{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x)
{
val = x;
}
}
public List<Integer> inOrder(TreeNode root)
{
List<Integer> list = new ArrayList<Integer>();
if(root == null)
return;
else
{
Stack<Integer> stack = new Stack<Integer>();
NodeTree Current = root;
while(Current != null || !stack.isEmpty())
{
while(Current != null)
{
stack.push(Current.val);
Current = Current.left;
}
if(!stack.isEmpty())
{
Current = stack.pop();
list.add(Current.val);
if(Current.right != null) //考虑左子树的右子树是否存在,如果存在,那么就将其压入栈中
Current = Current.right;
}
}
}
return list;
}
还有一种非递归的方式来中序遍历二叉树,因为上面那种方法来leetcode中发现超时了,所以得换一种方式:
public List<Integer> inOrder(TreeNode root)
{
List<Integer> list = new ArrayList<Integer>();
if(root == null)
return list;
else
{
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode Current = root;
while(Current != null || !stack.isEmpty())
{
if(Current != null)
{
stack.push(Current);
Current = Current.left;
}
else
{
TreeNode t = stack.pop();
list.add(t.val);
Current = t.right;
}
}
}
return list;
}
接下来是后续遍历:
首先采用递归的方式来实现后续遍历,与先序和中序遍历类似。
public void postOrder(TreeNode root)
{
if(root == null)
return;
else
{
if(root.left != null)
postOrder(root.left);
if(root.right != null)
postOrder(root.right);
System.out.println(root.val);
}
}
然后是非递归实现后续遍历,也是采用栈来实现,就是入栈和出栈顺序上得注意
public void thePostOrderTraversal_Stack(Node root) { //后序遍历
Stack<Node> stack = new Stack<Node>();
Stack<Node> output = new Stack<Node>();//构造一个中间栈来存储逆后序遍历的结果
Node node = root;
while (node != null || stack.size() > 0) {
if (node != null) {
output.push(node);
stack.push(node);
node = node.getRightNode();
} else {
node = stack.pop();
node = node.getLeftNode();
}
}
while (output.size() > 0) {
printNode(output.pop());
}
}