二叉树遍历
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
先序、中序、后序 (深度优先搜索DFS) 遍历思想
从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:
⑴访问结点本身(N),
⑵遍历该结点的左子树(L),
⑶遍历该结点的右子树(R)。
- NLR:前序遍历(Preorder Traversal 亦称(先序遍历))
访问根结点的操作发生在遍历其左右子树之前。
2.LNR:中序遍历(Inorder Traversal)
访问根结点的操作发生在遍历其左右子树之中(间)。
3.LRN:后序遍历(Postorder Traversal)
访问根结点的操作发生在遍历其左右子树之后。
递归实现
前序遍历:1 2 4 5 3 6 7 8
中序遍历:4 2 5 1 3 7 6 8
后序遍历:4 5 2 7 8 6 3 1
源代码如下:
class Node {
public int data;
public Node leftNode;
public Node rightNode;
Node(int data) {
this.data = data;
leftNode = null;
rightNode = null;
}
}
public class BinTree {
public static void main(String[] args) {
//构建二叉树操作
preOrderTraversal(n1);
System.out.println();
inOrderTraversal(n1);
System.out.println();
postOrderTraversal(n1);
}
public static void preOrderTraversal(Node node) { //先序遍历
if (node != null) {
System.out.print(node.data + " ");
preOrderTraversal(node.leftNode);
preOrderTraversal(node.rightNode);
}
}
public static void inOrderTraversal(Node node) { //中序遍历
if (node != null) {
inOrderTraversal(node.leftNode);
System.out.print(node.data + " ");
inOrderTraversal(node.rightNode);
}
}
public static void postOrderTraversal(Node node) { //后序遍历
if (node != null) {
postOrderTraversal(node.leftNode);
postOrderTraversal(node.rightNode);
System.out.print(node.data + " ");
}
}
}
非递归实现
源代码如下
public static void preOrderTraversal(Node root) { // 先序遍历
Stack<Node> s = new Stack<Node>();
Node p = root;
while (p != null || !s.isEmpty()) {
while (p != null) { // 将左节点全部压入栈中
System.out.print(p.data + " ");
s.push(p);
p = p.leftNode;
}
if (!s.isEmpty()) { // 左节点为空的情况下转向右子树
p = s.pop();
p = p.rightNode;
}
}
}
public static void inOrderTraversal(Node root) { // 中序遍历
Stack<Node> s = new Stack<Node>();
Node p = root;
while (p != null || !s.isEmpty()) {
while (p != null) { // 将左节点全部压入栈中
s.push(p);
p = p.leftNode;
}
if (!s.isEmpty()) { // 左节点为空的情况下转向右子树
p = s.pop();
System.out.print(p.data + " ");
p = p.rightNode;
}
}
}
public static void postOrderTraversal(Node root) { // 后序遍历
/*
* preOrderTraversal前序遍历顺序是:输出->左子树->右子树,postOrderTraversal后序遍历顺序是:左子树->右子树->输出
* 输出->右子树->左子树为后序遍历的逆序,将这些数据压入S2栈中,再一一出栈,即可的到二叉树的后序遍历
*/
Stack<Node> s1 = new Stack<Node>();
Stack<Node> s2 = new Stack<Node>();
Node p = root;
while (p != null || !s1.isEmpty()) {
while (p != null) { // 将右节点全部压入s1、s2栈中
s2.push(p); //System.out.print(p.data + " "); 可以输出后序遍历的逆序
s1.push(p);
p = p.rightNode;
}
if (!s1.isEmpty()) {
p = s1.pop();
p = p.leftNode;
}
}
while (!s2.isEmpty()) // 打印全部数据
System.out.print(s2.pop().data + " ");
}
层次遍历 (广度优先搜索BFS) 遍历思想
除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
二叉树层次遍历所用到的算法是广度优先搜索(Breadth First Search),广度优先搜索使用**队列(queue)**来实现,首先将把根节点放到队列的末尾;其次每次从队列的头部取出一个元素,查看这个元素所有的下一级元素(左右子树),把它们放到队列的末尾,直到完成遍历。
按照上图以此类推,直到队列为空。层次遍历:1 2 3 4 5 6 7 8。
源代码如下:
public static void LevelOrderTraversal(Node root) { // 层次遍历
Queue<Node> q = new LinkedList<Node>();
if (root == null)
return;
Node n = root;
q.offer(n);
while (!q.isEmpty()) {
n = q.poll();
System.out.print(n.data + " ");
if (n.leftNode != null)
q.offer(n.leftNode);
if (n.rightNode != null)
q.offer(n.rightNode);
}
}