前言
本章讲解二叉树的遍历策略及实现方法
方法
本章采用的二叉树示例:
1.概念
二叉树的遍历要求每个结点都必须访问一次,那么先左子树后右子树的规定,二叉树的遍历有以下三种方式:
- 先序遍历
所谓先序遍历,即根据“根,左子树,右子树”的顺序进行遍历。注意:子树的遍历也按照该策略循环往复。
按照示例的二叉树,其根为1,所以当前遍历的序列为——1
找到根1的左子树(4,5),按照先序遍历策略,所以当前遍历的序列为——4,5
找到根1的右子树(2,3,6),按照先序遍历策略,所以当前遍历的序列为——2,3,6
找到根6的右子树(7),按照先序遍历策略,所以当前遍历的序列为——7
所以最终的遍历结果为:1,4,5,2,3,6,7
- 中序遍历
所谓中序遍历,即根据“左子树,根,右子树”的顺序进行遍历。注意:子树的遍历也按照该策略循环往复。
按照示例的二叉树,找到根1的左子树(4,5),按照中序遍历策略,所以当前遍历的序列为——4,5
根1的左子树遍历完毕,遍历根1,按照中序遍历策略,所以当前遍历的序列为——1
按照示例的二叉树,找到根1的右子树(2,3,6),按照中序遍历策略,所以当前遍历的序列为——3,2,6
找到根6的右子树(7),按照先序遍历策略,所以当前遍历的序列为——7
所以最终的遍历结果为:4,5,1,3,2,6,7
- 后序遍历
所谓后序遍历,即根据“左子树,右子树,根”的顺序进行遍历。注意:子树的遍历也按照该策略循环往复。
按照示例的二叉树,找到根1的左子树(4,5),按照后序遍历策略,所以当前遍历的序列为——5,4
按照示例的二叉树,找到根1的右子树(2,3,6),按照后序遍历策略,所以当前遍历的序列为——3,6,2
找到根6的右子树(7),按照后序遍历策略,所以当7应排在6的前面
按照示例的二叉树,其根为1,所以当前遍历的序列为——1
所以最终的遍历结果为:5,4,3,7,6,2,1
练习:
已知一棵二叉树的后序遍历的序列为:5437621,中序遍历的序列为4513267,求其先序序列是什么?(同上例,请自主求解)
求解过程:
由后序遍历结果我们可以知道,其二叉树的根为1,那么由中序遍历可以知道其左子树为(4,5),右子树为(3,2,6,7)
我们不知道左子树(4,5)的排列情况,下面进行分析:
后序遍历是54,判断出左子树的根为4;中序遍历为45,判断出5为4的右子树。所以左半部分如下:
接下来判断右子树(3,2,6,7)的顺序,由于其大于四个,我们判断出其必然还有一层。
后序遍历是3762,所以其右子树根必为2;中序遍历为3267,所以根2的左子树必为叶子结点且为3
接下来判断(6,7)的位置关系:
由后序遍历76可以知道根2的右子树根为6,由中序遍历67表表明,7为根6的右子树。
可分析出其右半部分如下:
显然,左右合一便是我们例子中的二叉树,其先序遍历结果为:1,4,5,2,3,6,7
2.二叉树的遍历实现
1)创建相应工程
2)创建二叉树结点类
package cn.edu.ccut.tree;
/**
* 二叉树结点类
* @author jwang
*
*/
public class Node {
Object item; //数据对象
Node left;//左子树
Node right;//右子树
Node(Node left, Object element, Node right) {
this.item = element;
this.right = right;
this.left = left;
}
}
3)创建二叉树接口,列出基础方法
package cn.edu.ccut.tree;
/**
* 二叉树的接口
* @author jwang
*
*/
public interface BinaryTree {
public boolean isEmpty();//是否为空树
public int size();//树结点数量
public int getHeight();//获得树的深度(高度)
public void preOrderTraverse();//先序遍历
public void inOrderTraverse();//中序遍历
public void postOrderTraverse();//后序遍历
}
4)编写基于链式存储结构的二叉树实现类
package cn.edu.ccut.tree;
/**
* 二叉树的实现——链式存储结构
* @author jwang
*
*/
public class LinkedBinaryTree implements BinaryTree{
private Node root;//根结点
public LinkedBinaryTree(Node root) {
this.root = root;
}
public LinkedBinaryTree() {
}
@Override
public boolean isEmpty() {
return this.root == null;
}
@Override
public int size() {
return this.size(this.root);
}
private int size(Node root){
if(root == null){
return 0;
}else {
//获取左子树的数量
int leftSize = this.size(root.left);
//获得右子树的高度
int rightSize = this.size(root.right);
return leftSize+rightSize+1;//返回左右子树和加1
}
}
@Override
public void preOrderTraverse() {
System.out.println("--先序遍历--");
this.preOrderTraverse(this.root);
System.out.println();
}
//先序遍历辅助方法
private void preOrderTraverse(Node root){
if(root != null){
//输出根节点的值
System.out.print(root.item+" ");
//对左子树进行先序遍历
this.preOrderTraverse(root.left);
//对右子树进行先序遍历
this.preOrderTraverse(root.right);
}
}
@Override
public void inOrderTraverse() {
System.out.println("--中序遍历--");
this.inOrderTraverse(this.root);
System.out.println();
}
//中序遍历辅助方法
private void inOrderTraverse(Node root){
if(root != null){
//对左子树进行中序遍历
this.inOrderTraverse(root.left);
//输出根节点的值
System.out.print(root.item+" ");
//对右子树进行中序遍历
this.inOrderTraverse(root.right);
}
}
@Override
public void postOrderTraverse() {
System.out.println("--后序遍历--");
this.postOrderTraverse(this.root);
System.out.println();
}
//中序遍历辅助方法
private void postOrderTraverse(Node root){
if(root != null){
//对左子树进行后序遍历
this.postOrderTraverse(root.left);
//对右子树进行后序遍历
this.postOrderTraverse(root.right);
//输出根节点的值
System.out.print(root.item+" ");
}
}
@Override
public int getHeight() {
return getHeight(this.root);
}
//获取树的高度辅助方法
private int getHeight(Node root){
if(root == null){
return 0;
}else {
//获取左子树的高度
int leftHeight = this.getHeight(root.left);
//获得右子树的高度
int rightHeight = this.getHeight(root.right);
return Math.max(leftHeight, rightHeight)+1;//返回最大高度加1
}
}
}
5)编写测试类测试
package cn.edu.ccut.tree;
public class Test {
public static void main(String[] args) {
//创建一个二叉树
Node node5 = new Node(null, 5, null);
Node node4 = new Node(null, 4, node5);
Node node7 = new Node(null, 7, null);
Node node6 = new Node(null, 6, node7);
Node node3 = new Node(null, 3, null);
Node node2 = new Node(node3, 2, node6);
Node node1 = new Node(node4, 1, node2);
BinaryTree bTree = new LinkedBinaryTree(node1);
//是否为空二叉树
System.out.println(bTree.isEmpty());
//先序遍历结果
bTree.preOrderTraverse();
//中序遍历结果
bTree.inOrderTraverse();
//后序遍历结果
bTree.postOrderTraverse();
//树的高度
System.out.print("树的高度:"+bTree.getHeight());
System.out.println();
//树的结点数
System.out.print("树的结点数:"+bTree.size());
}
}
程序运行结果为:
其中的实现大量的运用递归的概念,希望大家细细体会其中的玄妙!