二叉树的遍历
二叉树遍历的经典方法有四种,前序遍历、中序遍历、后序遍历和层次遍历。
其中,前、中、后序,表示的是节点与它的左右子树节点遍历打印的先后顺序。
前序遍历是指,对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树。
中序遍历是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。
后序遍历是指,对于树中的任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印这个节点本身。
前中后序是DFS(深度优先算法)的思想
实际上,二叉树的前、中、后序遍历就是一个递归的过程。
前序遍历,其实就是先打印根节点,然后再递归地打印左子树,最后递归地打印右子树。
前序遍历的递推公式:
preOrder(r) = print r->preOrder(r.left)->preOrder(r.right)
中序遍历的递推公式:
inOrder(r) = inOrder(r.left)->print r->inOrder(r.right)
后序遍历的递推公式:
postOrder(r) = postOrder(r.left)->postOrder(r.right)->print r
递归实现
/**
* 先序遍历
*/
public static void preOrder(Node root) {
if (root == null) {
return;
}
System.out.print(root.value + " -> ");
preOrder(root.left);
preOrder(root.right);
}
/**
* 中序遍历
*/
public static void inOrder(Node root) {
if (root == null) {
return;
}
inOrder(root.left);
System.out.print(root.value + " -> ");
inOrder(root.right);
}
/**
* 后序遍历
*/
public static void postOrder(Node root) {
if (root == null) {
return;
}
postOrder(root.left);
postOrder(root.right);
System.out.print(root.value + " -> ");
}
非递归实现
递归本身是借助栈实现的,所以非递归的实现也需要栈来实现,本质上实际变成了我们“手动递归”
/**
* 前序遍历
*/
public static void preOrder2(Node root) {
if (root == null) {
return;
}
Stack<Node> s = new Stack<>();
s.push(root);
Node curNode;
while (!s.isEmpty()) {
curNode = s.pop();
System.out.print(curNode.data + "->");
// 栈先进后出,所以先加入右侧节点,这样输出的时候,先输出左侧节点
if (curNode.right != null) {
s.push(curNode.right);
}
if (curNode.left != null) {
s.push(curNode.left);
}
}
}
/**
* 中序遍历
*/
public static void inOrder2(Node root) {
if (root == null) {
return;
}
Stack<Node> s = new Stack<>();
Node curNode = root;
while (!s.isEmpty() || curNode != null) {
// 入栈所有左节点并输出左节点
while (curNode != null) {
s.push(curNode);
curNode = curNode.left;
}
// 弹出左节点
curNode = s.pop();
System.out.print(curNode.data + "->");
// 弹出后,指向当前节点的右节点
curNode = curNode.right;
}
}
/**
* 后序遍历
*/
public static void postOrder2(Node root) {
if (root == null) {
return;
}
Stack<Node> s1 = new Stack<>();
Stack<Node> s2 = new Stack<>();
s1.push(root);
Node curNode;
while (!s1.isEmpty()) {
curNode = s1.pop();
// 中、右、左顺序压入栈中
s2.push(curNode);
// 压入s1为先左后右,保证中、右、左顺序压入s2中
if (curNode.left != null) {
s1.push(curNode.left);
}
if (curNode.right != null) {
s1.push(curNode.right);
}
}
while (!s2.isEmpty()) {
System.out.print(s2.pop().data + "->");
}
}
层次遍历
层次遍历是BFS(广度优先算法)的思想。
一般借助于队列来实现二叉树的层次遍历。
层次遍历的步骤是:
1.对于不为空的结点,先把该结点加入到队列中
2.从队中拿出结点,如果该结点的左孩子不为空,就分别把左孩子加入到队列中,否则什么都不做。右孩子同理
3.重复以上操作直到队列为空,层次遍历结束
public static void LevelTraversal(Node root) {
if (root == null) {
return;
}
Queue<Node> queue = new LinkedList<Node>();
Node curNode = null;
queue.offer(root);//将根节点入队
while (!queue.isEmpty()) {
curNode = queue.poll();//出队队头元素并访问
System.out.print(curNode.data + "->");
if (curNode.left != null)//如果当前节点的左节点不为空入队
{
queue.offer(curNode.left);
}
if (curNode.right != null)//如果当前节点的右节点不为空,把右节点入队
{
queue.offer(curNode.right);
}
}
}