数据结构和算法(九)二叉树的遍历

前言

      本章讲解二叉树的遍历策略及实现方法

方法

本章采用的二叉树示例:

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());
	}

}

程序运行结果为:

其中的实现大量的运用递归的概念,希望大家细细体会其中的玄妙! 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值