二叉树(二)-----基本代码实现

    现在我想用代码来实现关于二叉树的一些基础功能。由于二叉树的功能比较多,所以我想多分几篇博客来叙述二叉树的功能。

    根据二叉树的结构和性质我们可以发现,二叉树的每个子节点都是其子节点的根节点,所以关于二叉树的很多功能实现都可以通过递归的方式来实现。关于我刚刚开始学习二叉树时,递归的思想让我十分头疼。递归的特点就是虽然代码看起来很简单,但是分析其具体内部实现过程却是十分复杂的。在我学习c++这本书时,遇到的汉诺塔问题,运用的就是递归思想。递归的应用就是栈中的出栈和入栈思想。最外层的方法先进栈,其中调用其本身,这个本身也是一个方法,可以看做方法的内部方法,这个内部方法再进栈。当然这样的进栈不是无休止的,否则就违反了程序的有限性原理。到了最底层满足跳出该方法的条件时,那么最底层的那个方法就会出栈,然后一层一层向上层方法出栈。所以在二叉树的各个方法实现中,我更愿意通过举例来深入详解二叉树所利用的递归思想。

    在讲述二叉树的基本性质之前,我需要先对二叉树的整体框架进行一个搭建。

    

public class BinaryTree {
	 private TreeNode root = null;
	
	 
	 public BinaryTree(){
		 root = new TreeNode(1,"A");
public class TreeNode{
		
		private int index;
		
		private String data;
		
		private TreeNode leftChild;
		
		private TreeNode rightchild;

		public TreeNode() {
			super();
		}
		public TreeNode(int index, String data) {
			super();
			this.index = index;
			this.data = data;
			this.leftChild = null;
			this.rightchild = null;
		}
		public int getIndex() {
			return index;
		}
		public void setIndex(int index) {
			this.index = index;
		}
		
		
		public String getData() {
			return data;
		}
		public void setData(String data) {
			this.data = data;
		}
		public TreeNode getLeftChild() {
			return leftChild;
		}
		public void setLeftChild(TreeNode leftChild) {
			this.leftChild = leftChild;
		}
		public TreeNode getRightchild() {
			return rightchild;
		}
		public void setRightchild(TreeNode rightchild) {
			this.rightchild = rightchild;
		}
		
		
	}

         }
	 }

一个内部类TreeNode以及一些简单的构造方法。


    首先我想先来讲述一下二叉树是怎样实现的。首先是二叉树的建立。

    在这里我以前序遍历的逆过程来实现二叉树生成。首先我们来看一棵二叉树。


这棵二叉树的前序遍历结果为 ABDECF

但是,我们在构建这棵二叉树的同时无法直接这样去构建。我们知道二叉树不是线性结构,我们需要将这课非完全二叉树补全为一个满二叉树


这样这棵二叉树的遍历结果就是ABD##E##C#F##。这样我们将这棵满二叉树进行构建即可。

下面是我的实现代码,我将慢慢解析我的代码

public TreeNode createBinaryTree(int size, List<String> list) {
		if(list.size()==0){
			return null;
		}
		String d = list.get(0);
		TreeNode node;
		int index = size - list.size();
		if(d.equals("#")){
			node = null;
			list.remove(0);
			return node;
		}
		node = new TreeNode(index,d);
		if(index ==0){
			root = node;
		}
		list.remove(0);
		node.leftChild = createBinaryTree(size,list);//createLeft
		node.rightchild =createBinaryTree(size,list);//createRight
		return node;
	}

首先来解释形参的含义,第一个size是指传入的链表的长度,第二个list是指二叉树的结点值的集合。

第一步如果list的大小为0。说明我们传入了一个空的list。这个时候返回null。终止二叉树的构造。

第二步,如果list的大小不为0.获取list的第一个元素的值,将其赋给d。之后我们声明一个结点,作为每次方法执行的用来定义为根节点的结点。

第三步,这里声明了一个index,这个index是用来定义插入的结点在list中的位置。

第四步,如果d的值为#,说明这个位置原本的结点应该为空。这个时候我们让node为null,同时list将头元素进行删除并将这个结点返回。即这个createBinaryTree方法的本次执行结束(注意,是本次执行而不是整棵二叉树的构造)。

第五步, 如果d不为#,那么对这个结点进行初始化。

第六步,如果index的值为0,说明这个结点是头结点。那么将root指向该结点。之后将该结点从list中删除(至于为什么每次都是list.remove(0),很简单,因为每次插入的都是新的list的第一个结点,因为它前面的结点都在之前的插入中remove了)

第七步,之后就是很重要的递归创建二叉树了,首先递归创建左子树,然后是递归创建右子树。

看似很简单但是分析起来却十分复杂。

下面就是我对这个构建过程的分析过程,由于递归的思想是类似的,在接下来的深度计算和结点计算中就不在同样叙述。


接下来我们来讨论一下怎样求出一棵树的深度

private int getDepth(TreeNode node) {
		if(node ==null){
			return 0;
		}else{
			int i = getDepth(node.leftChild);//lengthStatement1
			int j = getDepth(node.rightchild);//lengthStatement2
			return (i>j)?i+1:j+1;
		}
		
	}

同样是递归的思想,我们知道深度其实求一棵子树的最大层次。所以现在我来讲述一下这个算法。形参是这棵树的根节点,如果根节点是null则返回0.

其次首先试求根节点的左子树的深度,这个递归会一直执行下去知道传入的参数为null返回0。同理对右子树的遍历也是如此。

至于return (i>j)?i+1:j+1;这条语句。我们来简要分析一下,首先肯定是选择i和j中较大的内个。那么为什么要+1呢?每一层向上递归时,实际上都是向更高层次的出栈。所以要+1.


接下来是求一棵树的所有结点数。

private int getSize(TreeNode node) {
		if(node ==null){
			return 0;
		}
		return 1+getSize(node.leftChild)+getSize(node.rightchild);
	}



分析过程如上不再赘述。

下一篇专栏我将讲述关于树的三种遍历方式。

猜你喜欢

转载自blog.csdn.net/qq1641530151/article/details/80046891
今日推荐