引入:
这里我们来复习下二叉树的基本操作,这里假定我们定义一个有序二叉树,就是对于任意的节点,其如果有左子节点,那么左子节点的值一定小于该节点,如果有右子节点,则右子节点的值一定大于该节点。我们这里还给出代码表明如何前序,中序,后序来遍历这个二叉树。
实践:
我们先定义一个二叉树节点的类:
package com.charles.algo.binarytree;/** * 这个类定义了一个二叉树的节点 * @author charles.wang * */public class BinaryTreeNode { //二叉树中当前节点的内容 private Object data; //二叉树的左子节点 private BinaryTreeNode leftChild; //二叉树的右子节点 private BinaryTreeNode rightChild; public BinaryTreeNode(Object data,BinaryTreeNode leftChild,BinaryTreeNode rightChild){ this.data =data; this.leftChild=leftChild; this.rightChild=rightChild; } public Object getData() { return data; } public void setData(Object data) { this.data = data; } public BinaryTreeNode getLeftChild() { return leftChild; } public void setLeftChild(BinaryTreeNode leftChild) { this.leftChild = leftChild; } public BinaryTreeNode getRightChild() { return rightChild; } public void setRightChild(BinaryTreeNode rightChild) { this.rightChild = rightChild; } }
然后我们定义一个二叉树类,这个二叉树提供了插入节点,前序遍历,中序遍历,后序遍历的方法:
package com.charles.algo.binarytree;/** * 这里定义了一个基本的有序二叉树的数据结构 * @author charles.wang * */public class OrderedBinaryTree{ //用链表来实现排序二叉树的数据存储,这里放着根节点 private BinaryTreeNode rootNode; public OrderedBinaryTree(){ rootNode = null; } /** * 返回当前有序二叉树的最大高度 * @return */ public int getMaxHeight(){ return getHeight(rootNode); } /** * 基于当前树根节点确定子树的高度,这是一个递归的方法 * @return */ private int getHeight(BinaryTreeNode currentNode){ //如果当前树根节点为空,则返回 0 if(currentNode==null) return 0; //如果当前树根节点不为空,那么获取左子树高度和右字数高度的最大值 int maxLeftTreeHeight = getHeight(currentNode.getLeftChild())+1; int maxRightTreeHeight = getHeight(currentNode.getRightChild())+1; return Math.max(maxLeftTreeHeight, maxRightTreeHeight); } /** * 插入节点到当前的有序二叉树, */ public OrderedBinaryTree insertNode(Object data ){ //如果有序二叉树中rootNode为空,那么就直接新建一个节点并且赋值给root if(rootNode==null){ BinaryTreeNode binaryTreeNode = new BinaryTreeNode(data,null,null); rootNode=binaryTreeNode; return this; } //如果有序二叉树的rootNode不为空,那么就调用递归方法进行插入 else return insertNode(data,rootNode); } /** * 递归的插入一个节点到当前节点使得仍然保持 一个有序二叉树 */ public OrderedBinaryTree insertNode(Object data, BinaryTreeNode rootNode){ //创建一个代表当前待查数据的节点 BinaryTreeNode currentNode = new BinaryTreeNode(data,null,null); //吧当前的数据和被插入的rootNode的大小进行比较 //如果当前数据小于被插入的rootNode,那么这个新的数据节点必定插在rootNode的左边 if( (Integer)data< (Integer)rootNode.getData()){ //如果待插的rootNode的左节点为空,那么直接插入 if(rootNode.getLeftChild()==null){ rootNode.setLeftChild(currentNode); return this; } //如果待插的rotNode的左节点不为空,则递归的吧待插入点设为root的左节点,然后递归的调用方法插入 else return insertNode(data ,rootNode.getLeftChild()); } //如果当前数据大于被插入的rootNode,那么这个新的数据节点必定插在rootNode的右边 else { //如果待插的rootNode的右边节点为空,那么直接插入 if(rootNode.getRightChild()==null){ rootNode.setRightChild(currentNode); return this; } //如果待插的rootNode的右边节点不为空,则赌鬼的吧所待插入点设为root的右节点,然后递归调用方法插入 else return insertNode(data,rootNode.getRightChild()); } } /** * 前序遍历这个二叉树,并且打印出这个二叉树的各个节点 */ public void preOrderFullBinaryTree(){ preOrder(rootNode); } /** * 中序遍历这个二叉树,并且打印出这个二叉树的各个节点 */ public void midOrderFullBinaryTree(){ midOrder(rootNode); } /** * 后序遍历这个二叉树,并且打印出这个二叉树的各个节点 */ public void postOrderFullBinaryTree(){ postOrder(rootNode); } /** * 前序遍历某节点,它会先打印当前节点,然后打印出左边节点,然后打印出右边节点 */ private void preOrder(BinaryTreeNode currentNode){ //当前的节点如果是null,则不打印出当前节点,并且退出递归 if(currentNode!=null){ System.out.print(currentNode.getData()+" "); //遍历左边子树 preOrder(currentNode.getLeftChild()); //遍历右边子树 preOrder(currentNode.getRightChild()); } } /** * 中序遍历某节点,它会先打印左边节点,再打印当前节点,最后打印出右边节点 * @param args */ private void midOrder(BinaryTreeNode currentNode){ //当前节点如果是null,则不打印出当前节点,并且退出递归 if(currentNode!=null){ midOrder(currentNode.getLeftChild()); System.out.print(currentNode.getData()+" "); midOrder(currentNode.getRightChild()); } } /** * 后序遍历某个节点,它会先打印出左边节点,再打印出右边节点,最后打印出当前节点 * @param args */ private void postOrder(BinaryTreeNode currentNode){ //如果当前的节点是null,则不打印出当前节点,并且退出递归 if(currentNode!=null){ postOrder(currentNode.getLeftChild()); postOrder(currentNode.getRightChild()); System.out.print(currentNode.getData()+" "); } } public static void main(String[] args){ OrderedBinaryTree fbt = new OrderedBinaryTree (); fbt.insertNode(12).insertNode(5).insertNode(9).insertNode(11).insertNode(8).insertNode(42).insertNode(4); //前序遍历所有的节点 System.out.println("前序的方式遍历二叉树的所有的节点:"); fbt.preOrderFullBinaryTree(); System.out.println(); //中序遍历所有的节点 System.out.println ("中序的方式遍历二叉树的所有的节点:"); fbt.midOrderFullBinaryTree(); System.out.println(); //后序遍历所有的节点 System.out.println("后序的方式遍历二叉树的所有的节点:"); fbt.postOrderFullBinaryTree(); System.out.println(); }}
其实由于考虑到二叉树定义的递归性,我们上述方法都是用递归实现的,比如插入就是比较当前元素,如果插入元素比当前元素少,那么就比较当前元素的左子元素,如果左子元素不存在,那么新插入的元素就作为左子元素,否则就以左子元素为根,递归的插入该元素到左子二叉树中。反过来也一样,如果插入元素比当前元素大,那么久比较当前元素的右子元素,如果右子元素不存在,那么新插元素就作为右子元素,否则就以右子元素为根,递归的插入到该元素到右子二叉树中。
前序,中序,后序遍历也是一样的。
验证结果:
最后我们来运行这个简单的例子,果然是期望的,比如我们分别插入了果然的不一样的数,那么遍历结果顺序是不一样的但是都遍历二叉树的所有节点。