二叉树详解

1. 树结构

  • 树状图是一种数据结构,它是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点

        每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结点可以分为多个不相交的子树;

1.1 有关树结构的定义

  1. 节点的度:一个节点含有的子树的个数称为该节点的度;
  2. 叶节点或终端节点:度为0的节点称为叶节点;
  3. 非终端节点或分支节点:度不为0的节点;
  4. 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
  5. 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
  6. 兄弟节点:具有相同父节点的节点互称为兄弟节点;
  7. 树的度:一棵树中,最大的节点的度称为树的度;
  8. 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
  9. 树的高度或深度:树中节点的最大层次;
  10. 堂兄弟节点:双亲在同一层的节点互为堂兄弟;
  11. 节点的祖先:从根到该节点所经分支上的所有节点;
  12. 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
  13. 森林:由m(m>=0)棵互不相交的树的集合称为森林;

1.2 树的种类

无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;

有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;

二叉树:每个节点最多含有两个子树的树称为二叉树;

               完全二叉树

               满二叉树

霍夫曼树:带权路径最短的二叉树称为哈夫曼树或最优二叉树;

2. 二叉树

2.1 二叉树性质

(1) 在非空二叉树中,第i层的结点总数不超过  , i>=1;

(2) 深度为h的二叉树最多有  个结点(h>=1),最少有h个结点;

(3) 对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,N0=N2+1;

(4) 具有n个结点的完全二叉树的深度为  (注:[ ]表示向下取整)

(5)有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:

     若I为结点编号则 如果I>1,则其父结点的编号为I/2;

     如果2*I<=N,则其左孩子(即左子树的根结点)的编号为2*I;若2*I>N,则无左孩子;

     如果2*I+1<=N,则其右孩子的结点编号为2*I+1;若2*I+1>N,则无右孩子。

(6)给定N个节点,能构成h(N)种不同的二叉树。

    h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。

(7)设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和J=I+2i

2.1 利用Java代码实现简单的二叉树:

2.1.1 二叉树的遍历:

1:先序遍历(DLR)

  1):访问根节点;

  2):按先序遍历访问左子树

  3):按先序遍历访问右子树

2:中序遍历(LRD)

 1):按中序遍历左子树

 2):访问根节点

 3):按中序遍历访问右子树

3:后序遍历

 1):按后序遍历访问左子树

 2):按后序遍历访问右子树

 3):访问根节点

2.1.2 代码:

构造二叉树:

package com.xue.boke;
import java.util.ArrayList;
import java.util.List;
/**
 * 二叉树
 * @author xqp
 *
 */
public class BinTree {
	private BinTree lChild;//左孩子
	private BinTree rChild;//右孩子
	private BinTree root;//根节点
	private Object data;//数据域
	private List<BinTree> datas;//储存所有节点
	private int index = 0;//用于直到前序和中序生成后序遍历是寻找root节点
	public BinTree(BinTree lChild,BinTree rChild,Object data) {
		 this.lChild = lChild;
		 this.rChild = rChild;
		 this.data = data;
	}
	public BinTree(Object data){
		this(null,null,data);
	}
	public BinTree() {}
	public void createTree(Object[] obj){
		datas = new ArrayList<BinTree>();
		for (Object object : obj) {
			datas.add(new BinTree(object));
		}
		root = datas.get(0);//将第一个作为根节点
		for(int i = 0;i < obj.length/2; i++){
			datas.get(i).lChild = datas.get(i*2+1);
			if(i*2+2<datas.size()){
				datas.get(i).rChild = datas.get(i*2+2);
			}
		}
	}
	/**
	 * 打印节点
	 */
	private void visit(Object obj){
		System.out.print(obj+" ");
	}
	/**
	 *递归 方法 先序遍历 根-左-右
	 */
	public void preorder(BinTree root){
		if(root != null){
			visit(root.getData());
			preorder(root.lChild);
			preorder(root.rChild);
		}
	}
	/**
	 * 中序遍历 左-根-右
	 */
	public void inorder(BinTree root){
		if(root!=null){
			inorder(root.lChild);
			visit(root.getData());
			inorder(root.rChild);
		}
	}
	/**
	 * 后序遍历 左-右-根
	 */
	public void afterorder(BinTree root){
		if(root!=null){
			afterorder(root.lChild);
			afterorder(root.rChild);
			visit(root.getData());
		}
	}
	/**
	 * 已知前序遍历和中序遍历求后序遍历
	 */
	public void printAfter(String before ,String middle){
		if(middle.length() == 0){
			return;
		}
		//用于获取根节点的字符
		char root = before.charAt(index++);
		//获取根节点在中序遍历中出现的位置,以此切割中序遍历的字符串
		int i = middle.indexOf(root);
		//切分middle字符串,得到left和right两部分
		String left = middle.substring(0,i);
		String right = middle.substring(i+1);
		printAfter(before,left);//递归调用
		printAfter(before,right);
		visit(root);//打印节点字符
	}
	public BinTree getlChild() {
		return lChild;
	}
	public void setlChild(BinTree lChild) {
		this.lChild = lChild;
	}
	public BinTree getrChild() {
		return rChild;
	}
	public void setrChild(BinTree rChild) {
		this.rChild = rChild;
	}
	public BinTree getRoot() {
		return root;
	}
	public void setRoot(BinTree root) {
		this.root = root;
	}
	public Object getData() {
		return data;
	}
	public void setData(Object data) {
		this.data = data;
	}
	public List<BinTree> getDatas() {
		return datas;
	}
	public void setDatas(List<BinTree> datas) {
		this.datas = datas;
	}
}

测试代码:

package com.xue.boke;

public class treeTest {
	public static void main(String[] args) {
		BinTree binTree=new BinTree();
		Object[] obj={"A","B","C","D","E","F","G","H","I","J","K","L","M","N"};
		binTree.createTree(obj);
		System.out.println("先序遍历:");
		binTree.preorder(binTree.getRoot());// 先序遍历
		System.out.println();
		System.out.println("中序遍历:");
		binTree.inorder(binTree.getRoot()); //中序遍历
		System.out.println();
		System.out.println("后序遍历:");
		binTree.afterorder(binTree.getRoot()); //后序遍历
		System.out.println();
		System.out.println("----------------");
		String before = "ABDHIEJKCFLMGN"; 
		String middle = "HDIBJEKALFMCNG"; 
		System.out.println("已知前序遍历、中序遍历求后序遍历:");
		binTree.printAfter(before, middle);
	}
}

结果:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值