数据结构之树(Tree)(二)_二叉树的创建及遍历概述
树的第一部分(数据结构之树(Tree)(一)_树的基础)介绍了树的各个基础:什么是树、树的特点、树的表示方法、树的种类、树在存储结构中的表示、树/森林/二叉树之间的转换(原理)等。
这部分主要介绍下二叉树的创建及遍历(一种实现,主要了解二叉树遍历的过程)。遍历是二叉树重要的运算,是其他运算的基础。树、森林都可以转换成二叉树进行运算。
由于树的内容比较多,实现多样。关于二叉树的多种创建实现、二叉树的多种遍历(非递归、广度优先、深度优先等)实现、树转二叉树的实现 等后续整理总结。
二叉树遍历概述
根据二叉树的根结点及左、右子树遍历的次序,二叉树的遍历主要有3种方式。
- 先序遍历
先遍历根结点,再遍历左子树,最后遍历右子树。 - 中序遍历
先遍历左子树,再遍历根结点,最后遍历右子树。 - 后序遍历
先遍历左子树,再遍历右子树,最后遍历根结点。
如图,是一颗二叉树。遍历都是递归的方式。
先序遍历:ABDGHCEFI
中序遍历:BGDHAECIF
后序遍历:GHDBEIFCA
二叉树遍历的一种实现
二叉树先序遍历 创建树
上图看到的图像表示,人看了很容易理解。但在程序中需要通过一定规则实现它,这就需要创建树。(根据输入或者要求,创建实现方法多样,这里采用一种,多种创建方法后续总结。)
单个遍历结果(先序或者中序或者后序)无法确定一棵树的唯一样子。主要是单种遍历方式结果,你无法知道某个结点是否有孩子结点 还是仅有某个孩子结点,所以如果用#表示结点孩子结点不存在的位置,即某结点某方向在此停止,这样树的结构就确定了。然后通过这样的结果来创建树。
这样上图,先序遍历的结果就是:AB#DG##H##CE##FI###
注意:每个结点如果孩子结点不存在都要用#表示,即使是叶子结点也需要。
实现参考下面代码中的方法:createBinaryTree()。
创建及遍历的实现
具体看代码和注释,很容易理解:
public class BinaryTree { //二叉树结点定义:数据、左孩子、右孩子。 static class BinaryNode { Object data; BinaryNode leftChild, rightChild; public BinaryNode(Object data) { this.data = data; this.leftChild = this.rightChild = null; } } //根结点 static BinaryNode root; public BinaryTree() { root = null; } //用于先序遍历创建树的输入 static char[] treeNodes = "AB#DG##H##CE##FI###".toCharArray(); static int index = -1; //创建二叉树 public static BinaryNode createBinaryTree() throws Exception { BinaryNode newBinaryNode = null; index++; if (treeNodes[index] != ‘#‘) { newBinaryNode = new BinaryNode(treeNodes[index]); newBinaryNode.leftChild = createBinaryTree(); newBinaryNode.rightChild = createBinaryTree(); } //当碰到# 即newBinaryNode为null,即父结点没有某个孩子结点(左孩子或右孩子) 那条分支到这停止了。 return newBinaryNode; } //先序遍历 public static void preOrderTraversal(BinaryNode node) { if (node == null) return; System.out.print(node.data + " "); preOrderTraversal(node.leftChild); preOrderTraversal(node.rightChild); } //中序遍历 public static void inOrderTraversal(BinaryNode node) { if (node == null) return; inOrderTraversal(node.leftChild); System.out.print(node.data + " "); inOrderTraversal(node.rightChild); } //后序遍历 public static void postOrderTraversal(BinaryNode node) { if (node == null) return; postOrderTraversal(node.leftChild); postOrderTraversal(node.rightChild); System.out.print(node.data + " "); } public static void main(String[] args) { try { //创建二叉树,返回根结点 root = createBinaryTree(); System.out.println("创建成功!"); } catch (Exception e) { System.out.println("创建失败,请检查输入是否有误!"); e.printStackTrace(); } //分别用3种遍历方式,打印结果 System.out.println("先序遍历:"); preOrderTraversal(root); System.out.println(); System.out.println("中序遍历:"); inOrderTraversal(root); System.out.println(); System.out.println("后序遍历:"); postOrderTraversal(root); } }
从代码中看到输入的就是 AB#DG##H##CE##FI### ,让我们看下执行结果:
创建成功! 先序遍历: A B D G H C E F I 中序遍历: B G D H A E C I F 后序遍历: G H D B E I F C A
从结果看创建成功,遍历结果也与开始的一致:
先序遍历:ABDGHCEFI
中序遍历:BGDHAECIF
后序遍历:GHDBEIFCA