树和二叉数超级无敌详解(c语言版)

一、树的概念和结构(了解)

1.1 树的概念

之前我们学的链表、队列、栈都是线性数据结构,而树是我们第一个接触到的非线性的数据结构,它是由n个有限节点组成的一个具有层次关系的集合,可以联系到我们现实生活中的树,只不过要倒过来看,根在上,叶子在下,而一整棵树可以看成由若干的子树组成,可以看出树是递归定义的
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/3b748b31c29b4b11925acbdd5c93d3e5.png

接下来介绍几个树中常用的名词:

  1. 节点的度:一个节点含有的子树的个数称为该节点的度(B、C、D、E、F、G); 如上图:A的为6。
  2. 叶节点或终端节点:度为0的节点称为叶节点(可以理解成没孩子); 如上图:B、C、H、I…等节点为叶节点。
  3. 非终端节点或分支节点:度不为0的节点(有孩子); 如上图:D、E、F、G…等节点为分支节点。
  4. 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点。
  5. 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点。
  6. 兄弟节点具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点。
  7. 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6。
  8. 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推。(也可以将根算成第0层,但更推荐算成第1层)
  9. 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4。
  10. 节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先。
  11. 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙。
  12. 森林:由m(m>0)棵互不相交的多颗树的集合称为森林;(数据结构中的学习并查集本质就是一个森林)。

如何判断给定的图是不是树呢?
在这里插入图片描述

  1. 子树是不相交的
  2. 除根节点外每个节点只能有一个父亲
  3. N个节点有N-1条边

这里我给大家说一个最直接的办法,就是树不会成环,看见有环就不是树

1.2 树的表示

树的存储结构很复杂,也有很多的存储方式,例如:双亲表示法、孩子表示法、孩子兄弟表示法等等,这里我们了解一下最常用的孩子兄弟表示法。

typedef int DataType;
struct TreeNode
{
struct TreeNode* firstChild;  //第一个孩子结点
struct TreeNode* nextBrother;  //指向兄弟结点
DataType data;
}

我们来看图更加直观一点
在这里插入图片描述

二、二叉树的概念及结构

2.1二叉树的概念

二叉树(binary tree)是指树中节点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树。

两个特殊的二叉树:

  1. 满二叉树:除最后一层外,每个节点都有2个孩子,总节点数为2^n - 1,n为层数。
    在这里插入图片描述

  2. 完全二叉树:是一种特殊的满二叉树,就是在满二叉树的基础上,最后一层有序(从右往左)的缺失了一些结点,假如全部缺失了,就是满二叉树了。
    在这里插入图片描述

2.2二叉树的存储方式

  1. 顺序存储:就是用数组来存储二叉树,但一般只适用完全二叉树,不然会造成空间的浪费。学过堆排序同学应该知道。在物理结构上是数组,但是在逻辑上是棵树。 在这里插入图片描述

  2. 链式存储:二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给点左孩子和右孩子所在的链结点的存储地址。

typedef int BTDataType;
struct BinaryTreeNode
{
struct BinaryTreeNode* left;  //左孩子
struct BinaryTreeNode* right;  //右孩子
BTDataType data;  //存储数据
};

三、二叉树的性质

3.1性质

  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1) 个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h- 1(满二叉树).
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为 n0, 度为2的分支结点个数为 n2,则有n0=n2
    +1
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=LogN(等比求和反解得出)

3.2习题

  1. 某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( )
    A 不存在这样的二叉树
    B 200
    C 198
    D 199
    解析:利用性质三很快得出答案为199+1=200,B
  2. 在具有 2n 个结点的完全二叉树中,叶子结点个数为( )
    A n
    B n+1
    C n-1
    D n/2
    解析:二叉树的节点的度的情况只有3种,故设度为1的节点个数为a,度为2的节点个数为b,则度为0(叶子节点)的节点的个数为(b+1),又因为这是完全二叉树,根据该数的性质可以得出,度为1的节点的个数要么为0要么为1,故有2种情况 0+b+b+1=2n,解出b=(2n-1)/2。或者1+b+b+1=2n,解出b=n-1。综上答案为A
  3. 一棵完全二叉树的节点数位为531个,那么这棵树的高度为( )
    A 11
    B 10
    C 8
    D 12
    解析:根据二叉树的性质和完全二叉树的特点可得节点个数为2^h - 1 - x,其中h为高度,x为最后一层缺失的节点个数,范围是0~2^(i-1),将选项带入得出答案B
    答案:B A B

四、二叉树的遍历

4.1前序遍历(根、左子树、右子树)

void PrevOrder(struct BinaryTreeNode* root)
{
if(root == NULL)
return;  //遍历到空就返回
printf("%d",root->data);  //打印数据
prevOrder(root->left); //递归左子树
prevOrder(root->right);  //递归右子树
}

4.2中序遍历(左子树、根、右子树)

void InOrder(struct BinaryTreeNode* root)
{
if(root == NULL)
return;  //遍历到空就返回
InOrder(root->left); //递归左子树
printf("%d",root->data);  //打印数据
InOrder(root->right);  //递归右子树
}

4.3后序遍历(左子树、右子树、根)

void PostOrder(struct BinaryTreeNode* root)
{
if(root == NULL)
return;  //遍历到空就返回
PostOrder(root->left); //递归左子树
PostOrder(root->right);  //递归右子树
printf("%d",root->data);  //打印数据
}

4.4层序遍历(所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推)

void LeverOrder(struct BinaryTreeNode* root)
{
//这里队列函数就不展示了,主要看树
Queue q;
//要借助队列这个数据结构来实现
if(root == NULL)
{
return;
)
QueuePush(&q, root);  //根不为空将根(地址)入队列
while(!QueueEmpty(&q))  // 当队列为空时结束循环
{
struct BinaryTreeNode* tmp =  QueueFront(&q);  //取出队头的数据
printf("%d",tmp->data);  //打印队头数据
QueuePop(&q);  //出队列

//出队列的时候将自己的孩子带进队列
if(tmp->left != NULL)
{
QueuePush(&q,tmp->left);
}

if(tmp->right != NULL)
{
QueuePush(&q, tmp->right);
}

}
}

4.5几道选择题

  1. 某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为()
    A ABDHECFG
    B ABCDEFGH
    C HDBEAFCG
    D HDEBFGCA
    解析:层序输出则是一层一层按顺序从左往右输出,根据二叉树的性质先构造出二叉树!在这里插入图片描述

易得出前序序列为ABDHECFG
2. 二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为
()
A E
B F
C G
D H
解析:先从先序遍历顺序得出根E,然后在中序遍历,从根向左右分为左子树(HFI)和右子树(JKG),以此类推得到树的结构在这里插入图片描述
易得根节点为E

  1. 设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为____。
    A adbce
    B decab
    C debac
    D abcde
    解析:和上题类似,只需将后序遍历倒过来看,先找到根a,再通过中序遍历得到左子树(b)和右子树(dce),以此类推得到树的结构在这里插入图片描述
    易得前序遍历为abcde

答案:A A D

五、常见oj题

5.1二叉树的最大深度

int TreeDepth(struct BinaryTreeNode* root)
{
if(root == NULL)
return 0;

int leftDepth= TreeDepth(root->left);
int rightDepth = TreeDepth(root->right);

return (leftHeight > rightHeight)? leftHeight+1 : rightHeight+1;

}

5.2判断是否为平衡二叉树(每个节点的深度相差的绝对值不超过1)

bool IsBalance(struct BinaryTreeNode* root)
{
if(root == NULL)
return true;
return abs(TreeDepth(root->left) - TreeDepth(root->left)) <= 1 && IsBalance(root->left) && IsBalance(root->right)
}

5.3二叉树高度

int TreeHeight(struct BinaryTreeNode* root)
{
if(root == NULL)
return 0;

int leftHeight = TreeHeight(root->left);  //左树高度
int rightHeight = TreeHeight(root->right);  //右树高度

return (leftHeight > rightHeight)? leftHeight+1 : rightHeight+1;  //返回左、右高度高的高度再加上本身这一层高度(规定第一层高度为1不为0)

}

5.4构建及遍历二叉树

在这里插入图片描述

#include <stdio.h>
#include <stdlib.h>

//二叉树节点
struct BinaryTreeNode
{
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
char data;
};

//前序建立二叉树
struct BinaryTreeNode* CreatTree(char* s,int* pi)
{
//pi是记录访问的字符串的位置
if(s == NULL)
{
return NULL;
}

if(s[*pi] == '#')
{
(*pi)++;
return NULL;
}

struct BinaryTreeNode* Node = (struct BinaryTreeNode*)malloc(sizeof(struct BinaryTreeNode));
Node-> data = s[*pi];
(*pi)++;
Node->left = CreatTree(s,pi);
Node->right = CreatTree(s,pi);

return Node;
}

//中序遍历
void InOrder(struct BinaryTreeNode* root)
{
if(root == NULL)
return;  //遍历到空就返回
prevOrder(root->left); //递归左子树
printf("%d",root->data);  //打印数据
prevOrder(root->right);  //递归右子树
}

int main()
{
char s[100];
scanf("%s",s);
int i = 0;
struct BinaryTreeNode* root = CreatTree(s,&i);
InOrder(root);
return 0;
}

5.5节点个数

int TreeSize(struct BinaryTreeNode* root)
{
if(root == NULL)
return 0;
int left = TreeSize(root->left); //左树节点个数
int right = TreeSize(root->right);  //右树节点个数
return left + right + 1;  //返回左、右节点个数再加上本身
}

5.6叶子节点个数

int TreeLeafSize(struct BinaryTreeNode* root)
{
if(root == NULL)
return 0;
if(root->left == NULL && root->right == NULL)
return 1;
return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值