该文主要介绍2叉数的基本遍历的实现,在此之前,首先应该知道2叉数有哪些遍历?
先序遍历:根-->左-->右 即先访问根结点,然后访问左子树,最后访问右子树。在遍历左、右子树时,仍然如此。
上图遍历结果:A,B,D,E,C,F,G。
中序遍历:左-->根-->右 即先访问左子树,然后访问根结点,最后访问右子树。在遍历左、右子树时,仍然如此。
上图遍历结果:D,B,E,A,F,C,G。
后序遍历:左-->右-->根 即先访问左子树,然后访问右子树,最后访问根结点。在遍历左、右子树时,仍然如此。
上图遍历结果:D,E,B,F,G,C,A。
层次遍历:1层,2层,3层,依次访问下来,如果某一层元素超过两个,那么从先左后右访问。
上图遍历结果:A,B,C,D,E,F,G。(这个已经简单不行了)
深度遍历:首先访问根结点(A),然后沿着它的左结点依次访问(B,D),至到访问到最后一层(也就是D),再返回到它的父亲(B),访问他的右结点(E)。然后这样重复地访问完所有结点。
上图遍历结果:A,B,D,E,C,F,G。
备注:
1.上面的先、中、后序遍历,主要看的就是根在访问顺序中所在的位置。“根左右”,根在前,所以叫先序遍历。“左根右”,根在中,所以叫中序遍历。
2.在中序遍历中,有一种很快得出其遍历的结果的方法。叫做投影法。(你以为我会把这个方法的链接放在这里么?No,我只会告诉你,请百度百科“中序遍历”,这里有我想给你看的“投影法”。)
如何实现?
先序遍历:首先访问根,然后递归访问左子树,再递归访问右子树即可。
中/后序遍历:类似于先序遍历。等下看源码就明白了。
层次遍历
首先将根入队列(先进先出),然后就循环判断这个队列是否为空。只要队列不为空,就取出队列中的一个结点,访问这个结点的值,再将这个结点的左结点入队列,再将这个队列的右结点入队列。
层次遍历详细解释:
以上图的2叉数为例,首先将根A结点入队列,现在用while来循环判断队列是否为空。很明显,不为空。所以取出队列中的结点(A)来访问,然后,这个结点(A)的左结点(B)不为空,入队列,这个结点的右结点(C)也不为空,入队列。所以现在队列中就又有了B、C两个结点,所以循环继续。拿出B,访问B,再将B的左右结点D、E入队列。现在队列中就有了C、D、E了。队列不为空,所以循环继续,拿出C,访问C,再将F,G入队列。现在队列中就是D、E、F、G了。队列不为空,拿出D访问,D没有子结点,那么没有新的结点入队列,但队列还没有为空,所以接着拿出E来访问,E也没有子结点,所以也没有新的结点入队列,但队列还没有为空,接着再拿队列中的F来访问,依次类推了。(写得很罗嗦,希望能把这个过程解释清楚。)
深度遍历
首先将根入栈(先进后出),然后就循环判断这个栈是否为空。只要栈不为空,就取出栈中的一个结点,访问这个结点的值,再将这个结点的右结点入栈,再将这个结点的左结点入栈。(很类似于层次遍历的实现,只是所用的数据结构由队列变成了栈,入队列是先左后右,入栈的顺序是先右后左)
深度遍历详细解释:
这个很类似于层次遍历的详细解释,我简单得说一下。首先根A入栈,然后循环判断栈是否为空,现在栈里有结点A,所以不为空,所以取出A,访问A,将C、B入栈(也就是将A的右结点入栈,然后左结点入栈,和层次遍历时是相反的)。再判断栈是否为空,现在栈中有C、B。由于栈是后进先出的结构,所以这里是B弹出栈,访问B,再将B的子结点E、D入栈,那现栈中就有了C、E、D。判断栈不空,又弹出D,访问D,将D的子结点入栈。这样类推下去,就完成了遍历。
java代码如下:(有点多,不过该代码可测试运行)
package com.cdu.binaryTree;
import java.util.LinkedList;
public class MyBinaryTree {
public static void main(String[] args) {
//初始化一棵2叉数
BinaryTree binaryTree = BinaryTree.initBinaryTree();
// 先序遍历
System.out.println("先序遍历:");
binaryTree.preOrderTraversal(binaryTree);
System.out.println("\n");
// 中序遍历
System.out.println("中序遍历:");
binaryTree.midOrderTrversal(binaryTree);
System.out.println("\n");
// 后序遍历
System.out.println("后序遍历:");
binaryTree.postOrderTrversal(binaryTree);
System.out.println("\n");
// 层次遍历
System.out.println("层次遍历:");
binaryTree.levelTraversal(binaryTree);
System.out.println("\n");
// 深度遍历
System.out.println("深度遍历:");
binaryTree.depthTraversal(binaryTree);
System.out.println("\n");
}
}
class BinaryTree{
private int data; //结点值
private BinaryTree left; //左子结点
private BinaryTree right; //右子结点
public BinaryTree(int data){
this.data = data;
}
/**
* @Description 初始化二叉数
* @param
* @return 得到如下所示的二叉数
* 1
* * *
* 2 3
* * * * *
* 4 5 6 7
* * * *
* 9 10 11
* *
* 8
*
* 先序遍历结果:1,2,4,9,5,10,8,11,3,6,7
* 中序遍历结果:4,9,2,8,10,5,11,1,6,3,7
* 后序遍历结果:9,4,8,10,11,5,2,6,7,3,1
* 层次遍历结果:1,2,3,4,5,6,7,9,10,11,8
* 深度遍历结果:1,2,4,9,5,10,8,11,3,6,7
*/
public static BinaryTree initBinaryTree(){
BinaryTree root = new BinaryTree(1);
BinaryTree node2 = new BinaryTree(2);
BinaryTree node3 = new BinaryTree(3);
BinaryTree node4 = new BinaryTree(4);
BinaryTree node5 = new BinaryTree(5);
BinaryTree node6 = new BinaryTree(6);
BinaryTree node7 = new BinaryTree(7);
BinaryTree node8 = new BinaryTree(8);
BinaryTree node9 = new BinaryTree(9);
BinaryTree node10 = new BinaryTree(10);
BinaryTree node11 = new BinaryTree(11);
root.setLeft(node2);
root.setRight(node3);
node2.setLeft(node4);
node2.setRight(node5);
node3.setLeft(node6);
node3.setRight(node7);
node4.setRight(node9);
node5.setLeft(node10);
node5.setRight(node11);
node10.setLeft(node8);
return root;
}
/**
* @Description 先序遍历
* @param binaryTree 二叉数
* @return
*/
public void preOrderTraversal(BinaryTree binaryTree){
// 当2叉数为空时,递归结束。
if (binaryTree == null){
return ;
}else{
System.out.print(binaryTree.getData() + ","); //访问结点
preOrderTraversal(binaryTree.getLeft()); //递归遍历左子树
preOrderTraversal(binaryTree.getRight()); //递归遍历右子树
}
}
/**
* @Description 中序遍历
* @param binaryTree 二叉数
* @return
*/
public void midOrderTrversal(BinaryTree binaryTree){
if (binaryTree == null){
return ;
}else{
midOrderTrversal(binaryTree.getLeft());
System.out.print(binaryTree.getData() + ",");
midOrderTrversal(binaryTree.getRight());
}
}
/**
* @Description 后序遍历
* @param binaryTree 二叉数
* @return
*/
public void postOrderTrversal(BinaryTree binaryTree){
if (binaryTree == null){
return ;
}else{
postOrderTrversal(binaryTree.getLeft());
postOrderTrversal(binaryTree.getRight());
System.out.print(binaryTree.getData()+ ",");
}
}
/**
* @Description 层次遍历:先将根节点入队列,然后判断只要队列不为空,
* 那么就从队列中poll一个结点来访问,然后再将该结点的左结点入队列,然后再将右结点入队列
* @param
* @return
*/
public void levelTraversal(BinaryTree binaryTree){
LinkedList<BinaryTree> queue = new LinkedList<BinaryTree>();
if (binaryTree != null){
queue.offer(binaryTree);
}
// 只要队列不为空,则遍历队列中结点
while (!queue.isEmpty()){
BinaryTree node = queue.poll();
System.out.print(node.getData() + ",");
// 若结点有子结点,那么将该结点的左、右结点存入队列
if (node.getLeft() != null){
queue.offer(node.getLeft());
}
if (node.getRight() != null){
queue.offer(node.getRight());
}
}
}
/**
* @Description 深度遍历:先将根节点入队列,然后判断只要栈不为空,
* 那么就在栈中pop一个结点来访问,然后再将该结点的右结点压栈,然后再将左结点压栈
* @param
* @return
*/
public void depthTraversal(BinaryTree binaryTree){
LinkedList<BinaryTree> stack = new LinkedList<BinaryTree>();
if (binaryTree != null){
stack.push(binaryTree);
}
// 只要栈不为空,则遍历栈中结点
while(!stack.isEmpty()){
BinaryTree node = stack.pop();
System.out.print(node.getData() + ",");
// 若结点有子结点,那么将该结点的右、左结点存入队列
if (node.getRight() != null){
stack.push(node.getRight());
}
if (node.getLeft() != null){
stack.push(node.getLeft());
}
}
}
/*--------------getter and setter--------------------*/
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public BinaryTree getLeft() {
return left;
}
public void setLeft(BinaryTree left) {
this.left = left;
}
public BinaryTree getRight() {
return right;
}
public void setRight(BinaryTree right) {
this.right = right;
}
}