这里写目录标题
数据结构中有关树的一些定义
-
节点:节点包括一个数据元素及若干指向其子树的分支
-
节点的度:节点所拥有的子树的个数成为该节点的度
-
叶节点:度为0的节点称为叶结点
-
分支节点:度不为0的节点称为分支节点
-
树的度:树中所有节点的度的最大值
二叉树
二叉树是n(n>=0)个有限节点构成的集合。n=0的树称为空二叉树;n=1的树只有一个根结点;
n>1的二叉树由一个根节点和至多两个互不相交的,分别称为左子树和右子树的子二叉树构成
二叉树不是有序树,这是因为,二叉树中某个节点即使只有一个子树也要区分是左子树还是右子树;
而对于有序树来说,如果某个节点只有一个子树就必定是第一个子树
- 二叉树所有结点的5种形态:空节点,无左右子树节点,只有左子树节点,只有右子树节点和左右子树均存在的节点
- 满二叉树:在一棵二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子节点都在同一层,则这样的二叉树称作满二叉树
- 完全二叉树:如果一颗具有n个节点的二叉树的结构与满二叉树的前n个节点的结构相同,这样的二叉树称为完全二叉树
- 二叉树的性质:
- 若规定根节点的层数为0,则一棵非空二叉树的第i层上最多有2^i(i>=0)个节点
- 若规定只有根节点的二叉树的深度为0,则深度为k的二叉树的最大节点数是2^(k+1)-1(k>=-1)
- 对于一棵非空的二叉树,如果叶节点个数为n0,度为2的节点个数为n2,则有n0=n2+1
- 具有n个节点的完全二叉树的深度k为大于或等于ln(n+1)-1的最小整数
- 对于具有n个节点的完全二叉树,如果按照从上至下和从左至右的顺序对所有节点序号从0开始顺序编号,则对于序号为i(0<=i< n)的节点有:
如果i>0,则序号为i节点的双亲节点的序号为(i-1)/2(/为整除);如果i=0,则序号为i节点为根节点,无双亲节点 如果2i+1<n,则序号为i节点的左孩子节点的序号为2i+1;如果2i+1>=n,则序号为i节点无左孩子 如果2i+2<n,则序号为i节点的右孩子节点的序号为2i+2;如果2i+2>=n,则序号为i节点无右孩子
- 二叉树的存储结构
- 二叉树的顺序存储结构 利用性质5,对于完全二叉树可以利用一维数组存储,如果不是完全二叉树,则可以补空节点,使成为完全二叉树在进行存储,
但是对于非完全二叉树,可能要浪费很多的空间。 - 二叉树的链式存储结构 二叉树的链式存储结构就是用指针建立二叉树中节点之间的关系,二叉树最常用的链式存储结构是二叉链。二叉树的二叉链存储结构是一种常用的
二叉树存储结构。二叉链存存储结构的优点时,结构简单,可以方便的构造任何形状的二叉树,并可以方便的实现二叉树的大多数操作。
二叉链存储结构的缺点是,查找当前节点的双亲节点操作实现比较麻烦 - 二叉树的仿真指针存储结构 利用一维数组和结构体实现,利用数组的下标进行仿真指针进行二叉树的操作
代码实现
下面为具体代码实现:
package tree;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author xmhzwy@163.com @date: 2017-3-7
*
*/
public class BinTreeTraverse {
private int arr[]={1,2,3,4,5,6,7};
private static List<Node> nodeList=null;
private static class Node{
Node leftchild;
Node rightchild;
int data;
Node(int newdata){
leftchild=null;
rightchild=null;
data=newdata;
}
}
public void createBintree(){//新建一个二叉树
nodeList=new LinkedList<Node>();
for (int nodIndex = 0; nodIndex < arr.length; nodIndex++) {
nodeList.add(new Node(arr[nodIndex]));
}
//以下定义主要依据上面讲解的第五条的特性实现
for (int parentIndex = 0; parentIndex < arr.length/2-1; parentIndex++) {
//左孩子
nodeList.get(parentIndex).leftchild=nodeList.get(parentIndex*2+1);
//右孩子
nodeList.get(parentIndex).rightchild=nodeList.get(parentIndex*2+2);
}
//最后一个父节点,因为最后一个父节点可能没有右孩子,所以单独拿出来处理
int lastParentIndex=arr.length/2-1;
//左孩子
nodeList.get(lastParentIndex).leftchild=nodeList.get(lastParentIndex*2+1);
if (arr.length%2==1) {
nodeList.get(lastParentIndex).rightchild=nodeList.get(lastParentIndex*2+2);
}
}
/**
* 先序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void preOrderTraverse(Node node) {
if (node == null)
return;
System.out.print(node.data + " ");
preOrderTraverse(node.leftchild);
preOrderTraverse(node.rightchild);
}
/**
* 中序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void inOrderTraverse(Node node) {
if (node == null)
return;
inOrderTraverse(node.leftchild);
System.out.print(node.data + " ");
inOrderTraverse(node.rightchild);
}
/**
* 后序遍历
*
* 这三种不同的遍历结构都是一样的,只是先后顺序不一样而已
*
* @param node
* 遍历的节点
*/
public static void postOrderTraverse(Node node) {
if (node == null)
return;
postOrderTraverse(node.leftchild);
postOrderTraverse(node.rightchild);
System.out.print(node.data + " ");
}
public static void main(String[] args) {
BinTreeTraverse binTree = new BinTreeTraverse();
binTree.createBintree();
// nodeList中第0个索引处的值即为根节点
Node root = nodeList.get(0);
System.out.println("先序遍历:");
preOrderTraverse(root);
System.out.println();
System.out.println("中序遍历:");
inOrderTraverse(root);
System.out.println();
System.out.println("后序遍历:");
postOrderTraverse(root);
}
}
输出的结果为:
先序遍历:
1 2 4 5 3 6 7
中序遍历:
4 2 5 1 6 3 7
后序遍历:
4 5 2 6 7 3 1