1. 树结构
每个结点有零个或多个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结点可以分为多个不相交的子树;
1.1 有关树结构的定义
- 节点的度:一个节点含有的子树的个数称为该节点的度;
- 叶节点或终端节点:度为0的节点称为叶节点;
- 非终端节点或分支节点:度不为0的节点;
- 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
- 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
- 兄弟节点:具有相同父节点的节点互称为兄弟节点;
- 树的度:一棵树中,最大的节点的度称为树的度;
- 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推;
- 树的高度或深度:树中节点的最大层次;
- 堂兄弟节点:双亲在同一层的节点互为堂兄弟;
- 节点的祖先:从根到该节点所经分支上的所有节点;
- 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
- 森林:由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);
}
}
结果: