提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
树:是由n个结点构成的有限集合T。
有序树:计算机的存储是有序的,为方便计算机处理,往往把子结点按从左到右的次序顺序编号,即把树作为有序树(ordered tree)看待。(结点的子树在树中的位置固定,不能互换)
二叉树
定义:
二叉树的递归定义∶二叉树是n个结点的有限集合,该集合或者为空(n=0),或者由一个根结点及两棵互不相交的左、右子树构成,而其左、右子树又都是二叉树。
满二叉树∶如果一棵二叉树中任意一层的结点个数都达到了最大值,则此二叉树称为满二叉树。一棵高度为k的满二叉树具有2k一1个结点
删除一些结点时,编号不变。
完全二叉树:对于深度为k,有n个结点的完全二叉树,其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应。(编号连续)
满二叉树也属于完全二叉树
完全二叉树的特征∶
(1)叶子结点只可能在层次最大的两层上出现。
(2)任一结点,若其左分支下的子孙的最大层次为l,则其右分支下的最大层次为l域l-1,即若某结点无左子树,则该结点一定没右子树。
(3)满二叉树必为完全二叉树,而完全二叉树不一定是满二叉树。
5号结点的左孩子=52,右孩子=52+1
二叉树的性质
性质1︰一棵非空二叉树的第﹔层上最多有2i-1个结点(i≥1) 。
性质2∶一棵高度为k的二叉树,最多具有2k一1个结点。
二叉树的存储结构
顺序存储
二叉树的顺序存储结构就是一组地址连续的存储单元依次自上而下,自左而右地存储二叉树中的结点,并且在存储结点的同时,结点的存储位置(下标)应能体现结点之间的逻辑关系。
顺序实现的特点:
1.造成存储空间的浪费:最坏的情况下,一个深度为k且只有k个结点的右单支二叉树需要2k-1个存储单元
2.一般只用于一些特殊场合,如静态的并且结点个数已知的完全二叉树或接近完全二叉树的二叉树。
链式存储结构
由于二叉树的每个结点最多有两个孩子,因此可以设置两个指针域left和right,分别指向该结点的左孩子和右孩子,当结点的某个孩子为空时,则相应的指针置为空指针。这种结点结构称为二叉链表结点。
若二叉树中经常进行的操作是寻找结点的双亲,每个结点还可以增加一个指向双亲的指针域parent,根结点的parent指针置为空指针。这种结点结构称为三叉链表结点
二叉树的二叉链表的表示和实现
template <class elemType>
class BinaryLinkList{
private:
struct Node{//二叉链表结点
Node *left , *right ;//指向左右孩子的指针
elemType data;//结点的数据域
Node(): left(NULL), right(NULL){}//无参构造
Node(elemType value,Node *( = NULL,Node *r =NULL)
{data=value; left=l; right=r;}
-Nodel(){}
二叉树的遍历
遍历二叉树,是指按一定的规则和顺序访问二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。
由于二叉树是非线性结构,因此,二叉树的遍历实质上是将二叉树的各个结点排列成为一个线性序列。
1.深度优先遍历包括︰前序、中序和后序遍历
2.广度优先即层次遍历﹔是指沿着二叉树的宽度遍历二叉树的结点,即从上至下从左到右逐层遍历二叉树的结点。
前序遍历
如果二叉树为空,则操作为空否则,访问根结点前序遍历左子树前序遍历右子树(根左右)
中序遍历:
中序遍历左子树,访问根结点,中序遍历右子树(左根右)
后序遍历
后序遍历左子树,后序遍历右子树,访问根结点。(左右根)
前序:ALBECDWX
中序:BLEACWXD
后序:BELXWDCA
层次:ALCBEDWX
递归前序遍历
template <class elemType>
void BinaryLinkList<elemType>:: preOrder(Node *t) const{
if (t){
cout <<t->data << '';//访问当前结点
preOrder(t->left);//前序遍历左子树
preOrder(t->right);//前序遍历右子树
}
}
层次序遍历
由于队列具有先进先出的特点,因此可以借助队列实现层次遍历
算法思想:
(1)初始化一个队列,并把根结点入队﹔
(2)当队列非空时,循环执行步骤3到步骤5,否则遍历结束;(3)出队一个结点,并访问该结点﹔
(4)若该结点的左子树非空,则将其的左子树入队﹔(5)若该结点的右子树非空,则将其的右子树入队﹔
template <class elemType>
void BinaryLinkList<elemType>::levelOrderTraverse() const{
queue<Node*> que;//STL中的队列
Node* p = root;
if(p) que.push(p);//根节点入队列
while (!que.empty()){//队列非空
p = que.front();//取队首元素
que.pop();//出队
cout << p->data <<' ';//访问当前结点
if (p->left != NULL)que.push(p->left);//左子树进队列
if (p->right!= NULL)que.push(p->right);//右子树进队列
}
}
二叉树结构的性质
1.已知二叉树的先序序列和中序序列,可以唯一确定一棵二叉树。
2.已知二叉树的后序序列和中序序列,可以唯一确定一棵二叉树﹔
3.已知二叉树的先序序列和后序序列,不能唯一确定一棵二叉树;
4.已知二叉树的层次序列和中序序列,可以唯一确定一棵二叉树。
例题:
求结点总数
基于前序递归遍历的思想,求二叉树的结点总数的算法描述如下∶递归前序遍历二叉树:
(1)若为空子树,则该子树结点数为0
(2)若子树非空,则该子树的结点总数=1(当前结点)+左子树的结点数+右子树的结点数。
template <class elemType>
int BinaryLinkList<elemType>:.size(Node *t) const{
if (t == NULL) return O;//情况(1)∶空子树
return 1 + size(t->left) + sizeit->right);//情况(2)∶子树非空
}