欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数据结构之树

程序员文章站 2022-04-25 16:49:34
...

  • 基本概念 

是n(n>=0)个结点的有限集。n=0的时候称为空树。在任意一棵非空树中:(1)有且仅有一个特定的称为根结点

(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2.....、Tn,其中么一个集合本身又是一棵树,并且称之为根的子树(SubTree)。

如下图所示

数据结构之树

结点的度:结点拥有的子树数称为结点的度。度为0结点称为叶子结点或者终端结点,度不为0的结点称为非终端结点或者分支结点。除根结点外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。

数据结构之树

层次与深度:结点的层次从根开始定义起,根为第一层,根的子树为第二层。若某结点在第i层,则其子树的根就在第i+1层。其双亲在同一层的结点互为堂兄弟。显然下图中的D、E、F是堂兄弟,G、H、I、J也是。树中结点的最大层次称为树的深度或高度,当前树的深度是4。

数据结构之树

种类:

无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为*树;
有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;
二叉树:每个节点最多含有两个子树的树称为二叉树;
数据结构之树

完全二叉树:在一棵二叉树中如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上;
数据结构之树

满二叉树:对一棵具有n个结点的二叉树按层序编号,如果编号为i(1<=i<=n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则为完全二叉树
数据结构之树

树的存储结构:结合顺序存储和链式存储来实现主要有:

双亲表示法:在每个结点中,附设一个指示器指示其双亲结点到链表中的位置,缺点就是要知道父结点下有哪几个子结点比较麻烦。

数据结构之树 数据结构之树

孩子表示法:

数据结构之树

孩子兄弟表示法:任意一棵树,它的结点的第一个孩子如果存在就是唯一的,它的右兄弟如果存在也是唯一的。因此我们设置两个指针,分别指向该结点的第一个孩子和此结点的右兄弟。

数据结构之树

数据结构之树

最终方案:把每个结点的孩子结点排列起来,以单链表作为存储结构,则n个结点有n个孩子链表,如果是叶子结点则此单链表为空,然后n个头指针又组成一个线性表,采用顺序存储结构,存放在一维数组中。类似与java1.7中hashmap的数据结构

数据结构之树

  • 二叉树

二叉树的性质:

性质1:在二叉树的第i层上至多有2i-1个结点(i>=1)。
性质2:深度为k的二叉树至多有2k-1个结点(k>=1)。
性质3:对任何一颗二叉树T,如果其终端结点数为n0,度为2的 结点 数为n2,则n0 = n2+1.
性质4:具有n个结点的完全二叉树深度为[log2n]+1 ([x]表示不 大于 x的最大整数)。
性质5:如果对一颗有n个结点的完全二叉树(其深度为[log2n]+1) 的结点按层序编号(从第1层到第[log2n]+1层,每层从左到 右),对任意一个结点i(1<=i<=n)有:
1).如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结 点[i/2]
2).如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩 子是结点2i。

3).如果2i+1>n,则结点i无右孩子;否则其右孩子是结点2i+1。

二叉树的遍历:

前序遍历:规则是若二叉树为空,则空操作返回,否则先访问根结点,然后前序遍历左子树,在前序遍历右子树。

即 根 左 右

数据结构之树

伪代码:

void ProOrderTraverse(Tree T){
	if(T == null){
		return;
	}
	printf(“%c”,T-data);         //根
	ProOrderTraverse(T->lchild);//左
	ProOrderTraverse(T->rchild);//右
}

中序遍历:规则是若树为空,则空操作返回,否则从根结点开始(注意并不是访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树

即 左 根 右 

数据结构之树

伪代码

void ProOrderTraverse(Tree T){
	if(T == null){
		return;
	}
	ProOrderTraverse(T->lchild); //左
	printf(“%c”,T-data);        //中
	ProOrderTraverse(T->rchild);//右
}

后序遍历:规则是若树为空,则空操作返回,否则从左到右先叶子结点的方式遍历左右子树,最后访问根结点

即 左 右 根 

数据结构之树

伪代码

void ProOrderTraverse(Tree T){
	if(T == null){
		return;
	}
	ProOrderTraverse(T->lchild); //左
	ProOrderTraverse(T->rchild); //右
	 printf(“%c”,T-data);        //根
}

 下面给出Java的实现

public class BinTree<T> {

//建立以下的树的数据结构

//     A

//  B   C

//  D  E    F

//G

Node<T> root;


public BinTree(){

root = new Node(0,"A");

}

//构造数据

public void createTree(){

Node nodeB = new Node(1,"B");

Node nodeC = new Node(2,"C");

Node nodeD = new Node(3,"D");

Node nodeE = new Node(4,"E");

Node nodeF = new Node(5,"F");

Node nodeG = new Node(6,"G");

root.left = nodeB;

root.right = nodeC;

nodeB.left = nodeD;

nodeB.right = nodeE;

nodeC.right = nodeF;

nodeD.left = nodeG;

}

//前序遍历 根 左 右

public void preOrder(Node<T> root){

if(root == null){

return;

}

//获取遍历的数据

System.out.println(root.data);

preOrder(root.left);

preOrder(root.right);

}


//中序遍历 左 根 右

void midOrder(Node<T> root){

if(root == null){

return;

}

//获取遍历的数据


midOrder(root.left);

System.out.println(root.data);

midOrder(root.right);

}

//后续遍历 左 右 根

public void postOrder(Node<T> root){

if(root == null){

return;

}

//获取遍历的数据

postOrder(root.left);

postOrder(root.right);

System.out.println(root.data);

}

//获取结点树

public int size(Node<T> root){

if(root == null){

return 0;

}

return size(root.left) + size(root.right) + 1;

}

//获取深度

public int length(Node<T> root){

if(root == null){

return 0;

}

return length(root.left)>length(root.right)?length(root.left)+1:length(root.right) +1;

}

//数据结构类

private class Node<T>{

Node<T> right;//左结点

Node<T> left;//右结点

T data;//数据

int index;

public Node(int index,T data){

this.data = data;

this.index = index;

}

}

}




相关标签: