第五次

树和二叉树

树的定义

树:n(n≥0)个结点的有限集合。当n=0时,称为

空树;任意一棵非空树满足以下条件:

(1)有且仅有一个特定的称为根的结点;

⑵当n>1时,除根结点之外的其余结点被分成m (m>0)个互不相交的有限集合T1,T2,…
,Tm,其中每个集合又是一棵树,并称为这个根结点的子树。

树的基本术语

【1】结点的度:结点所拥有的子树的个数。

【2】树的度:树中各结点度的最大值。

【3】叶子结点:度为0的结点,也称为终端结点。

【4】分支结点:度不为0的结点,也称为非终端结点。

【5】孩子、双亲:树中某结点子树的根结点称为这个结点的孩子结点,这个结点称为它孩子结点的双亲结点;兄弟:具有同一个双亲的孩子结点互称为兄弟。

【6】路径:如果树的结点序列n1,
n2, …, nk有如下关系:结点ni是ni+1的双亲(1<=i<k),则把n1, n2, …, nk称为一条由n1至nk的路径;路径上经过的边的个数称为路径长度。

【7】祖先、子孙:在树中,如果有一条路径从结点x到结点y,那么x就称为y的祖先,而y称为x的子孙。

【8】结点所在层数:根结点的层数为1;对其余任何结点,若某结点在第k层,则其孩子结点在第k+1层。

【9】树的深度:树中所有结点的最大层数,也称高度。

【10】层序编号:将树中结点按照从上层到下层、同层从左到右的次序依次给他们编以从1开始的连续自然数。

【11】有序树、无序树:如果一棵树中结点的各子树从左到右是有次序的,称这棵树为有序树;反之,称为无序树。数据结构中讨论的一般都是有序树

【12】森林:m (m≥0)棵互不相交的树的集合。

树的遍历:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
孩子兄弟表示法:

结点结构 firstchild data rightsib

data:数据域,存储该结点的数据信息; firstchild:指针域,指向该结点第一个孩子; rightsib:指针域,指向该结点的右兄弟结点。

template

struct TNode

{

T data;

TNode *firstchild, *rightsib; };

二叉树的定义:

二叉树是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。

二叉树的特点:

⑴ 每个结点最多有两棵子树;

⑵二叉树是有序的,其次序不能任意颠倒。

特殊的二叉树:

(1)斜树

1 .所有结点都只有左子

树的二叉树称为左斜树;

2 .所有结点都只有右子树的二叉树称为右斜树; 3.左斜树和右斜树统称为

斜树。

  1. 在斜树中,每一层只有一个结点;斜树的特点:

2.斜树的结点个数与其深度相同。

(2)满二叉树

在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子

都在同一层上。

满二叉树的特点:

  1. 叶子只能出现在最下一层;

  2. 只有度为0和度为2的结点。

完全二叉树:

对一棵具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中的位置完全相同。

完全二叉树的特点:

  1. 叶子结点只能出现在最下

两层,且最下层的叶子结点 H 都集中在二叉树的左部;

  1. 完全二叉树中如果有度为1的结点,只可能有一个,且该结点只有左孩子。

  2. 深度为k的完全二叉树在 k-1层上一定是满二叉树。

※二叉树的基本性质

性质5-1 二叉树的第i层上最多有2i-1个结点(i≥1)。

性质5-2
一棵深度为k的二叉树中,最多有2k-1个结点,最少有k个结点。

性质5-3
在一棵二叉树中,如果叶子结点数为n0,度为2的结点数为n2,则有: n0=n2+1。

性质5-4
具有n个结点的完全二叉树的深度为log2n +1。证明:假设具有n个结点的完全二叉树的深度为k,根据完全二叉树的定义和性质2,有下式成立

2k-1 ≤ n < 2k k所在区间对不等式取对数,有:

k-1≤log2n<k ⎣ log2n⎦ log2n ⎣ log2n ⎦ +1 log2n + 1 即:

   log2n<k≤log2n+1      

由于k是整数,故必有k=⎣ log2n ⎦ +1。

说明:符号⎣x⎦表示不大于x的最大整数。

性质5-5
对一棵具有n个结点的完全二叉树中从1开始按层序编号,则对于任意的序号为i(1≤i≤n)的结点(简称为结点i),有:

(1)如果i>1,则结点i的双亲结点的序号为 i/2;如果 i=1,则结点i是根结点,无双亲结点。

(2)如果2i≤n,则结点i的左孩子的序号为2i;如果2i>n,则结点i无左孩子。

(3)如果2i+1≤n,则结点i的右孩子的序号为2i+1;如果2i+1>n,则结点 i无右孩子。

二叉树的遍历操作:

前序遍历序列:A B D G C E F

中序遍历序列:D G B A E C F

后序遍历序列:G D B E F C A

层序遍历序列:A B C D E F G

二叉链表存储结构的类声明 :

void PreOrder(BiNode *root);

void InOrder(BiNode *root);

void PostOrder(BiNode *root);

void LevelOrder(BiNode *root);

private:

BiNode *root;

void
Creat(BiNode *root);

void Release(BiNode *root);

};

前序遍历——递归算法

template

void
BiTree::PreOrder(BiNode *root)

{

if
(root ==NULL) return;

else { cout<data;

PreOrder(root->lchild);

PreOrder(root->rchild);

}

}

中序遍历——递归算法

template

void BiTree::InOrder
(BiNode *root)

{ if (root==NULL) return;

else {

InOrder(root->lchild);

cout<data;

InOrder(root->rchild);

}

后序遍历——递归算法

template

void
BiTree::PostOrder(BiNode *root)

{

if (root==NULL) return;

else {

PostOrder(root->lchild);

PostOrder(root->rchild);

cout<data;

}

}

层序遍历

template

void
BiTree::LevelOrder(BiNode *root)

{const int MaxSize = 100; int front = 0;

int rear = 0; //采用顺序队列,并假定不会发生上溢

BiNode* Q[MaxSize];
BiNode* q; if (root==NULL) return; else{

Q[rear++] = root; while (front != rear)

{ q = Q[front++]; cout<data<<"
"; if (q->lchild != NULL)
Q[rear++] = q->lchild; if (q->rchild != NULL) Q[rear++] = q->rchild;

}

}

}

二叉树的建立

设二叉树中的结点均为一个字符。假设扩展二叉树的前序遍历序列由键盘输入,root为指向根结点的指针,二叉链表的建立过程是:

首先输入根结点,若输入的是一个“#”字符,则表明该二叉树为空树,即root=NULL;否则输入的字符应该赋给root->data,,之后依次递归建立它的左子树和右子树。

template

BiTree ::BiTree(BiNode
*root)

Creat(root);

建立二叉树递归算法 {({ )

}

template

void BiTree
::Creat(BiNode *root)

cin>>ch;

if (ch==’# ') root=NULL;

else {

root=new BiNode; root->data=ch;

Creat(root->lchild);

Creat(root->rchild);

}

}

template BiTree
::BiTree()

建立二叉树递归算法 {root =Creat ();

}

template BiNode*
BiTree ::Creat()

{
BiNode* root; T ch; cin>>ch; if (ch==’# ') root=NULL;

else {

root=new BiNode; root->data=ch;
root-> lchild=Creat(); root-> rchild=Creat();

} return root;

}

二叉树的销毁

二叉链表是动态存储分配,在析构函数中释放二叉链表的所有结点。

注意:先释放掉某结点的左、右子树才能释放这个结点。

所以,采用后序遍历,对结点的访问就是释放该结点。

template

BiTree::~BiTree(void)

{

Release(root); }

二叉树的销毁递归算法 {

template

void
BiTree::Release(BiNode* root)

if (root != NULL){

Release(root->lchild); //释放左子树 Release(root->rchild); //释放右子树 delete
root;

}

}

遍历二叉树是二叉树各种操作的基础,遍历算法中对每个结点的访问操作可以是多种形式及多个操作,根据遍历算法的框架,适当修改访问操作的内容,可以派生出很多关于二叉树的应用算法。

void
InOrder (BiNode *root)

{ if (root==NULL) return; else {

InOrder(root->lchild);
cout<data; InOrder(root->rchild);

}

}

设计算法求二叉树的结点个数。

int n=0; template void
Count(BiNode *root) //n为全局量并已初始化为0

{ if (root) {

Count(root->lchild); n++;

Count(root->rchild);

}

}

设计算法按前序次序打印二叉树中的叶子结点。

template void PreOrderleaf(BiNode
*root)

{ if (root) { if (!root->lchild
&& !root->rchild) cout<data;

PreOrderleaf(root->lchild);

PreOrderleaf(root->rchild); }

}

设计算法求二叉树的深度。

template

int Depth(BiNode *root)

{ if (root==NULL) return 0; else {

int hl=Depth(root->lchild); int
hr=Depth(root ->rchild); return hl>hr?hl+1:hr+1;

}

} 用孩子-兄弟表示法表示树,设计算法求树中结点 x 的第 i 个孩子。

用孩子-兄弟表示法表示树,设计算法求树中结点 x 的第 i 个孩子。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值