树
树是一种非常重要的非线性数据结构。
树的树形图表示法规定在用直线连接起来的两端结点中,处在上端的结点是前驱,处在下端的结点是后继。
树的逻辑结构可表示为T=(D,R);
数据元素集合:D={A,B,C,D,E,F,G,H,I,J,K,L}
树的定义
树是由n(n≥0)个结点组成的有限集T。当n=0时,称为空树;当n>0时,集合T需满足如下条件:
1、有且仅有一个没有前驱的结点,该结点称为树的根节点。
2、将根节点去除后,其余结点可分为m(m≥0)个互不相交的子集T1、T2、...、Tm,其中每个子集Ti(i=1,2,3...m)又是一棵树,并称其为根的子树。
树的定义采用的是递归定义方式。
树的表示方法
1、树形图
2、嵌套集合表示法
嵌套集合表示法是通过包含的形式体现结点之间的关系,后继结点集合包含在前驱结点集合中。
3、凹入表表示法
凹入表表示法是利用树的目录形式表示结点之间的关系,后继结点位于前驱结点的下一层目录中。
4、广义表表示法
广义表表示法是利用广义表的多层次结构来表示树,后继结点位于前驱结点的下一层次。
树的基本术语
度:一个结点的后继的数目称为该结点的度。
树的度:树中各结点度的最大值称为树的度。
结点的层:树的根结点所在的层为第一层,其余结点的层等于其前驱结点的层加1。
树的深度:树中各结点的层的最大值称为树的深度。
分支:从一个结点到其后继结点之间的连线称为一个分支。
路径:从一个结点x到另一个结点Y所经历的所有分支构成结点x到结点Y的路径。
路径长度:一条路径上的分支数目称为路径长度。
树的路径长度:从树的根结点到其他各个结点的路径长度之和称为树的路径长度。
叶子结点(终端结点):树中度为0的结点称为叶子结点。
分支结点(非终端结点):度不为0的结点称为分支结点。
内部结点:除根结点以外的分支结点也称为内部结点。
结点间的关系:在树中,一个结点的后继结点称为该结点的孩子,一个结点的前驱结点称为该结点的双亲;同一个双亲结点的孩子结点称为兄弟,不同双亲但在同一层的结点之间胡称为堂兄弟;从树的根结点到某一个结点X的路径上经过的所有结点(包括根结点但不包括x结点)称为x结点的祖先。以某一结点x为根的子树上的所有非根结点(除结点x外)称为结点x的子孙。
有序树和无序树:对于树中任一结点,如果其各子树的相对次序被用来表示数据之间的关系,即交换位置会改变树表示的内容,称为有序树,否则称为无序树。
森林:m(m≥0)棵互不相交的树的集合构成森林。
二叉树
二叉树是一种特殊的树结构。
二叉树的定义也采用递归定义方式。
二叉树是有n(n≥0)个结点组成的有限集T。当n=0时,称为空二叉树;当n>0时,集合T需要满足如下条件:
- 有且仅有一个没有前驱的结点,该结点称为二叉树的根结点;
- 将根结点去除后,其余结点可分为两个互不相交的子集T1、T2,其中每个子集Ti(i=1,2)又是一棵二叉树,并分别称为根结点的左子树和右子树。
二叉树定义:二叉树是每个结点的度都小于等于2的有序树。
二叉树的5种基本形态:
二叉树的顺序编号法:对二叉树中的结点可以按照“自上而下,自左至右”的顺序进行连续编号,称为顺序编号法。
满二叉树和完全二叉树是两种特殊形态的二叉树。
满二叉树:是指除了最后一层的结点为叶子结点外其它结点都有左、右两棵子树的二叉树。
完全二叉树:是指其结点与相同深度的满二叉树中的结点编号完全一致的二叉树。对于深度为k的完全二叉树,其前k-1层与深度为k的满二叉树的前k-1层完全一样,只是在第k层有可能缺少右边若干个结点。
满二叉树必然是完全二叉树,而完全二叉树不一定是满二叉树。
二叉树的性质:
- 在二叉树的第i层上至多有2^(i-1)个结点。
- 深度为k的二叉树至多有(2^k)-1个结点。
- 在二叉树中,若度为0的结点(即叶子结点)数为n0,度为2的结点数为n2,则 n0=n2+1;
- 具有n个结点的完全二叉树其深度为⌊㏒2ⁿ⌋+1 (其中⌊㏒2ⁿ⌋表示不大于㏒2ⁿ的最大整数)。
- 采用顺序编号的完全二叉树具有如下性质
- 若一个分支结点的编号为i,则其左子树(即左孩子结点)的根节点编号为2xi,右子树(即右孩子结点)的根节点编号为2xi+1;
- 若一个非根结点的编号为i,则其双亲结点的编号为⌊i/2⌋ (其中⌊i/2⌋表示不大于i/2的最大整数)。
二叉树的基本操作
- 创建一棵空二叉树;
- 删除一棵二叉树;
- 先序遍历二叉树;
- 中序遍历二叉树;
- 后序遍历二叉树
- 逐层遍历二叉树;
- 判断二叉树是否为空;
- 清空二叉树;
- 以指定元素值创建根节点;
- 将一个结点作为指定结点的左孩子插入;
- 将一个结点作为指定结点的右孩子插入;
- 删除以指定结点为根的子树;
- 按关键字查找结点;
- 修改指定结点的元素值;
- 获取指定结点的双亲结点;
- 计算二叉树的深度;
- 计算二叉树的叶子结点数;
二叉树的抽象数据类型
ADT BinTree
{
Data:
具有二叉树型结构的0或多个相同类型数据元素的集合
Operations:
BinTree(); //创建空二叉树
~BinTree(); //删除二叉树
PreOrderTraverse(); //先序遍历
InOrderTraverse(); //中序遍历
PostOrderTraverse(); //后序遍历
LevelOrderTraverse(); //逐层遍历
IsEmpty(); //判断二叉树是否为空
CreateRoot(); //以指定元素值创建根结点
Clear(); //清空二叉树
InsertLeftChild(); //将一个结点作为指定结点的左孩子插入
InsertRightChild(); //将一个结点作为指定结点的右孩子插入
DeleteSubTree(); //删除以指定结点为根的子树
SearchByKey(); //按关键字查找结点
ModifyNodeValue(); //修改指定结点的元素值
GetParent(); //获取指定结点的双亲结点
}ADT BinTree;
二叉树的顺序表示
把二叉树的结点按照完全二叉树的顺序编号规则自上而下、自左至右依次存放在一组地址连续的存储单元里构成了二叉树的顺序存储,树中结点的编号就可以唯一地反映出结点之间的逻辑关系。
通常通过定义一个一维数组来表示二叉树的顺序存储空间。
为了使数组元素的下标值与其对应的结点编号一致,将下标为0的空间空闲不用或用作其他用途。
二叉树的顺序表示法操作方便,但缺点是容易造成存储空间浪费。
二叉树顺序表示适用于完全二叉树而不适用于非完全二叉树。
二叉树的链式表示
链式表示通常具有更高的空间利用率,因此在实际应用中一般会使用链式表示来存储二叉树。
根据一个结点中指针域数量的不同,二叉树的链式表示又可以分为二叉链表表示和三叉链表表示。
二叉链表表示
在二叉链表表示中,双亲结点有指向其孩子结点的指针,而孩子结点不包括指向其双亲结点的指针。
二叉树中每个结点最多有两个孩子,因此在一个结点中设置两个指针域leftchild和rightchild分别指向其左孩子和右孩子,数据域data用于存放每个结点中数据元素的值。
如果一个结点没有左孩子,leftchild指针为空(用NULL或0表示),如果一个结点没有右孩子,rightchild指针为空(用NULL或0表示)。
三叉链表表示
在三叉链表表示中,双亲结点有指向其孩子结点的指针,而孩子结点也包含指向其双亲结点的指针。
在用三叉链表表示的二叉树的每个结点中,除了具有二叉链表中的两个指向孩子结点的指针域leftchild和rightchild外,还有一个指向双亲结点的指针域parent。
根结点没有双亲,所以它的parent指针为空(用0或NULL表示)。
二叉链表结点类模板
二叉树二叉链表类模板
二叉链表的实现