树的定义
树的定义:树(Tree)是n(n≥0)个结点的有限集。n=0 时称为空树。在任意一棵非空树中:
(1)有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1、T2、……、Tm,其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)。
对于树的定义还需要强调两点:
1.n>0 时根结点是唯一的,不可能存在多个根结点,别和现实中的大树混在一起,现实中的树有很多根须,那是真实的树,数据结构中的树是只能有一个根结点。
2.m>0时,子树的个数没有限制,但它们一定是互不相交的。像图 中的两个结构就不符合树的定义,因为它们都有相交的子树。
节点分类
树的结点包含一个数据元素及若干指向其子树的分支。结点拥有的子树数称为结点的度(Degree)。
度为0的结点称为叶结点(Leaf)或终端结点;
度不为0的结点称为非终端结点或分支结点。
除根结点之外,分支结点也称为内部结点。树的度是树内各结点的度的最大值。
节点间的关系
结点的子树的根称为该结点的孩子(Child),相应地,该结点称为孩子的双亲(Parent)。同一个双亲的孩子之间互称兄弟(Sibling)。
结点的祖先是从根到该结点所经分支上的所有结点。所以对于H来说,D、B、A都是它的祖先。反之,以某结点为根的子树中的任一结点都称为该结点的子孙。
树的其他相关概念
结点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层。若某结点在第1层,则其子树的根就在第1+1层。其双亲在同一层的结点互为堂兄弟。显然图中的 D、E、F 是堂兄弟,而G、H、I、J也是。树中结点的最大层次称为树的深度(Depth)或高度,当前树的深度为4。
如果将树中结点的各子树看成从左至右是有次序的,不能互换的,则称该树为有序树,否则称为无序树。
对比线性表与树的结构
线性结构 树结构
第一个数据元素:无前驱 根结点:无双亲,唯一
最后一个数据元素:无后继 叶结点:无孩子,可以多个
中间元素:一个前驱一个后继 中间结点:一个双亲多个孩子
二叉树的遍历
树的创建
/*创建一颗二叉树*/
TREE_NODE *create_Btree()
{
BTDATA_TYPE data = tree[idx++];
if (data == '#')
{
return NULL;
}
TREE_NODE *pnode = malloc(sizeof(TREE_NODE));
if (NULL == pnode)
{
perror("fail malloc");
return NULL;
}
pnode->data = data;
pnode->pl = create_Btree();
pnode->pr = create_Btree();
return pnode;
}
前序遍历
/*前序遍历一颗二叉树*/
void pre_order(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
printf("%c", proot->data);
pre_order(proot->pl);
pre_order(proot->pr);
}
中序遍历
/*二叉树的中序遍历*/
void mid_order(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
mid_order(proot->pl);
printf("%c", proot->data);
mid_order(proot->pr);
}
后序遍历
/*二叉树的后序遍历*/
void pos_order(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
pos_order(proot->pl);
pos_order(proot->pr);
printf("%c", proot->data);
}
获取节点个数
int get_btree_node_cnt(TREE_NODE *proot)
{
if (NULL == proot)
{
return 0;
}
return 1+get_btree_node_cnt(proot->pl)+get_btree_node_cnt(proot->pr);
}
获取树的深度
int get_btree_layer_cnt(TREE_NODE *proot)
{
if (NULL == proot)
{
return 0;
}
int layL = get_btree_layer_cnt(proot->pl);
int layR = get_btree_layer_cnt(proot->pr);
return layL > layR ? layL+1 : layR+1;
}
销毁树
void destroy_btree(TREE_NODE *proot)
{
if (NULL == proot)
{
return ;
}
destroy_btree(proot->pl);
destroy_btree(proot->pr);
free(proot);
}
层序遍历
void layer_order(TREE_NODE *proot)
{
QUE_LIST *pque = create_link_queue();
if (NULL == pque)
{
return ;
}
DATA_TYPE outdata;
QUE_NODE *pnode = create_node(proot);
push_queue(pque, pnode);
while (!is_empty_queue(pque))
{
pop_queue(pque, &outdata);
printf("%c", outdata->data);
if (outdata->pl != NULL)
{
pnode = create_node(outdata->pl);
push_queue(pque, pnode);
}
if (outdata->pr != NULL)
{
pnode = create_node(outdata->pr);
push_queue(pque, pnode);
}
}
destroy_queue(pque);
}
二叉树的性质
二叉树(Binary Tree)是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
二叉树特点
二叉树的特点有:
■每个结点最多有两棵子树,所以二叉树中不存在度大于 2 的结点。注意不是只有两棵子树,而是最多有。没有子树或者有一棵子树都是可以的。
■左子树和右子树是有顺序的,次序不能任意颠倒。
■即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。
满二叉树
在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树称为满二叉树。
完全二叉树
对一棵具有 n个结点的二叉树按层序编号,如果编号为i(1<i<n)的结点与同样深度的满二叉树中编号为 i的结点在二叉树中位置完全相同,则这棵二叉树称为完全二叉树。
二叉树的特点:
(1)叶子结点只能出现在最下两层。
(2)最下层的叶子一定集中在左部连续位置。
(3)倒数二层,若有叶子结点,一定都在右部连续位置。
(4)如果结点度为1,则该结点只有左孩子,即不存在只有右子树的情况。
(5)同样结点数的二叉树,完全二叉树的深度最小。
二叉树的性质
性质1:在二叉树的第i层上至多有2的(i-1)次方个结点(i>1)。
性质2:深度为k的二叉树至多有2*-1个结点(*>1)。
性质3:对任何一棵二叉树 T,如果其终端结点数(叶子节点)为n,度为2的结点数为m,则n=m+1。
性质 4:具有n个结点的完全二叉树的深度为[log2(2为底)n]+1。([x]表示不大于x的最大整数)。