树
一、树的定义
树(Tree)是n(n≥0)个结点的有限集。n = 0时称为空树。在任意一颗非空树中:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T~1~、T~2~、……、T~m~,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。
1.当n>0时,每棵树的根结点是唯一的;
2.子树个数没有限制,但一定是唯一的。
二、相关概念
1.结点:一个数据元素以及若干指向子树的分支,度(结点拥有的子树数)为0的节点称为叶结点或终端结点;度不为0的结点称为非终端结点或分支结点。除根结点之外,分支结点也成为内部结点。
树的度取树内各结点度的最大值。
2.结点关系:结点的子树的根称为该结点的孩子,则该结点为孩子的双亲,同一个双亲的孩子之间互称兄弟。结点的祖先是从跟到该结点所经分支上的所有结点,反之,以某结点为根的子树中的任一结点都称为该结点的子孙。
3.结点的层次:根为第一层,往下依次加一。树中结点的最大层次称为树的深度或高度。
4.森林:森林是m(m≥0)棵互不相交的树的集合。对树中每个结点而言,其子树的集合即为森林。
三、树的结构
1.双亲表示法:
以一串连续空间存储树的结点,在每个结点中设置一个指向双亲结点的指针,树的结构就可表示为结点数组和根结点位置组成的结构体;
结构代码如下:
#define MAX_TREE_SIZE 100
typedef int TElemType; /*树的结点数据类型,设为int*/
typedef struct PTNode /*结点数组*/
{
TElemType data; /*结点数据*/
int parent; /*双亲位置*/
}PTNode;
typedef struct /*树结构*/
{
PTNode nodes[MAX_TREE_SIZE]; /*结点数组*/
int r, n; /*根的位置和结点数*/
}
2.孩子表示法:
每个结点有多个指针,指向其子树的根结点,这种表示法也叫多重链表表示法。具体方法是,将每个结点的孩子结点排列,以单链表存储,n个头指针组成线性表结构顺序存储,也可以在头结点加入指向双亲的指针,便于查找。
孩子表示法的结构代码如下:
#define MAX_TREE_SIZE 100
typedef struct CTNode /*孩子结点*/
{
int child;
struct CTNode *next;
}*ChildPtr;
typedef struct /*表头结构*/
{
TElemType data;
ChildPtr firstchild;
int parent; /*双亲位置*/
}CTBox;
typedef struct /*树结构*/
{
CTBox nodes[MAX_TREE_SIZE];
int r,n;
}CTree;
3.孩子兄弟表示法:
在一个结点中设置两个指针,分别指向左孩子和右兄弟。
结构定义如下:
typedef struct CSNode
{
TElemType data;
struct CSNode *firstchild,*rightsib;
}CSNode,*CSTree;
四、二叉树
在孩子兄弟表示法中,可以看到,一棵树可以转化为二叉树。二叉树(Binary Tree)是n(n≥0)个结点的有限集合,该集合或者为空集(空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
二叉树的特点:
- 每个结点最多有两棵子树;
- 左子树和右子树有顺序,不可颠倒。
二叉树的分类:
- 斜树:所有结点只有左子树的二叉树叫左斜树,所有结点只有右子树的二叉树叫右斜树;
- 满二叉树:在一棵二叉树中,如果所有结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树;
- 完全二叉树:对一颗具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
二叉树的性质:
- 在二叉树的第i层上至多有2^i-1^个结点(i≥1);
- 深度为k的二叉树至多有2^k^-1个结点(k≥1);
- 叶子结点数为度为2的结点数加一;
- n个结点的完全二叉树深度为(lgn+1);
二叉树的结构:
每个节点包括一个数据域、左指针和右指针。
二叉树的结构代码如下:
typedef struct BiTNode /*节点结构*/
{
TElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode,*BiTNode;
五、相关算法(源码内容)
1.二叉树遍历:
- 先序遍历:
graph LR
根-->左
左-->右
- 中序遍历:
graph LR
左-->根
根-->右
- 后序遍历:
graph LR
左-->右
右-->根
- 层序遍历:
graph LR
上-->下
左-->右
下-->左
右-->下
2.赫夫曼树:
构造方法:
- 将每个字符看做一棵树,按权值从小到大排列为集合T;
- 取最小权值的两棵树组合成一棵树,根结点的权值为两权值之和,在T中去掉这两棵树,换为根结点,重新排列。
- 重复第二步,直到组合完成。
赫夫曼解码需要编码为前缀编码,可规定左边全为0,右边全为1。
赫夫曼结点结构如下:
class HuffNode {
private Character data;
private HuffNode lchild;
private HuffNode Rchild;
private HuffNode parent; /*父结点*/
private int weight; /*结点权重*/
private int Flag; /*Flag为0表示未插入树中,为1表示已插入*/
private String code; /*结点的赫夫曼码*/
}
3.二叉排序树:
特点:
- 若左子树不为空,左子树上所有的值小于其根结点的值;
- 若右子树不为空,右子树上所有的值大于其根结点的值;
- 它的左、右子树也分别为二叉排序树。
最好构建平衡二叉树,提高查找效率。
4.平衡二叉树(AVL树):
平衡二叉树是一种二叉排序树,其中每一个结点的左子树和右子树的高度至多等于1。
最小不平衡子树:
距离插入结点最近的,且平衡因子的绝对值大于1的结点为根的子树,称为最小不平衡子树。
平衡二叉树构建方法:
在构建二叉排序树的过程中,每当插入一个结点时,先检查是否破坏了树的平衡性,若是,则找出最小不平衡子树,调整各结点位置,进行相应的旋转,使之成为新的平衡二叉树。
平衡二叉树结点结构如下:
class AVLNode{
private int data;
private AVLNode lchild;
private AVLNode rchild;
private int height; //结点高度
}
5.红黑树:
红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树增加了如下的额外要求:
- 节点是红色或黑色。
- 根节点是黑色。
- 每个叶节点(NIL节点,空节点)是黑色的。
- 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
- 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
红黑树的结点结构:
class Node{
private Key key; //键
private Value value; //值
private Node left, right; //指向子树的链接:左子树和右子树.
private int N; //以该节点为根的子树中的结点总数
boolean color; //结点颜色,红或黑
}
附上各个算法代码链接: