此模块为学校数据结构必修课学习内容的记录与分享
全文大体分为一下几个部分
- 背景
- 分析
- 代码
- 结果
- Points
- 概念辨析
- 易错题本
- 高质视频推荐
背景
二叉树是每个节点最多有两个子树的树结构,这两个子树分别被称为左子树和右子树。二叉树的子树有左右之分,次序不能颠倒。
二叉树在算法、数据压缩、数据库索引、编译器设计等领域都有重要应用,例如在哈夫曼编码中,通过构建二叉树来实现数据的压缩;在二叉搜索树中,利用二叉树的特性实现高效的数据查找、插入和删除操作。
分析
按照上面的描述,二叉树的结构单元需要具备左右节点指针和数据单元,因此也不难写出其对应结构体:
typedef struct BTtree {
char data;
struct BTtree *left;
struct BTtree *right;
}BTNode, *BTreePtr;
代码
还差一点code
#include<stdio.h>
#include<malloc.h>
#define QUEUE_SIZE 5
typedef struct BTtree {
char data;
struct BTtree *left;
struct BTtree *right;
}BTNode, *BTreePtr;
// 下面采用的是循环队列
typedef struct BTQueue {
// 可以看作是指针数组,储存一个个树节点
BTreePtr *NodePtrs;
int front;
int rear;
}*BTQueuePtr;
BTQueuePtr InitQueue() {
BTQueuePtr Q = (BTQueuePtr)malloc(sizeof(BTQueue));
Q->NodePtrs = (BTreePtr*)malloc(sizeof(BTNode) * QUEUE_SIZE);
Q->front = 0;
Q->rear = 1;
return Q;
}
bool IsEmpty(BTQueuePtr Q) {
return (Q->front + 1) % QUEUE_SIZE == Q->rear;
}
void EnQueue(BTQueuePtr Q, BTreePtr x) {
if ((Q->rear + 1) % QUEUE_SIZE == Q->front) {
printf("Queue is full\n");
return;
}// of if
Q->NodePtrs[Q->rear] = x;
Q->rear = (Q->rear + 1) % QUEUE_SIZE;
}
BTreePtr DeQueue(BTQueuePtr Q) {
if (IsEmpty(Q)) {
printf("Queue is empty\n");
return NULL;
}// of if
// 由初始化两个索引值分别为 0 和 1 ,因此这里必须front先++,再输出数据
Q->front = (Q->front + 1) % QUEUE_SIZE;
printf("DeQueue: %c\n", Q->NodePtrs[Q->front]->data);
BTreePtr x = Q->NodePtrs[Q->front];
return x;
}
BTreePtr ConstructBTreeNode (char data) {
BTreePtr NewNode = (BTreePtr)malloc(sizeof(BTNode));
NewNode->data = data;
NewNode->left = NewNode->right = NULL;
return NewNode;
}
BTreePtr string2BtreeNode (char *str) {
int i;
char ch;
BTQueuePtr Q = InitQueue();
BTreePtr ResultHeader;
BTreePtr TempParent, TempLeftChild, TempRightChild;
i = 0;
ch = str[i];
// 构建根节点
ResultHeader = ConstructBTreeNode(ch);
// 将根节点入队
EnQueue(Q, ResultHeader);
while (!IsEmpty(Q)) {
// 从队列中取出一个节点作为当前父节点
TempParent = DeQueue(Q);
// 处理左子节点
i++;
ch = str[i];
if (ch == '#') {
// 如果字符为 #,表示左子节点为空
TempParent->left = NULL;
} else if (ch == ')') {
// 构建左子节点
TempLeftChild = ConstructBTreeNode(ch);
// 将左子节点入队
EnQueue(Q, TempLeftChild);
// 将左子节点连接到父节点
TempParent->left = TempLeftChild;
}// of if
// 处理右子节点
i++;
ch = str[i];
if (ch == '#') {
// 如果字符为 #,表示右子节点为空
TempParent->right = NULL;
} else if (ch == ')') {
// 构建右子节点
TempRightChild = ConstructBTreeNode(ch);
// 将右子节点入队
EnQueue(Q, TempRightChild);
// 将右子节点连接到父节点
TempParent->right= TempRightChild;
} // of if
} // of while
} // of string2BtreeNode
void BFS(BTreePtr root) {
char TempStr[100];
int i = 0;
BTQueuePtr Q = InitQueue();
BTreePtr TempNode;
EnQueue(Q, root);
while (!IsEmpty(Q)) {
TempNode = DeQueue(Q);
TempStr[i++] = TempNode->data;
if (TempNode->left != NULL) {
EnQueue(Q, TempNode->left);
}
if (TempNode->right != NULL) {
EnQueue(Q, TempNode->right);
}
}
printf("%s\n", TempStr);
printf("The end : %s",TempStr);
free(Q);
free(TempNode);
free(TempStr);
return;
}
int main () {
return 0;
}
概念辨析
完全二叉树
n-1层都无空缺且n层满足“尽可能左边连续”的二叉树
explanation
你的疑问非常关键,我们来澄清“完全二叉树”的定义,并结合“高度为 8”来严格推理:
✅ 完全二叉树的正式定义是:
- 对于一个有高度为 hh 的二叉树,
- 它的前 h−1h – 1 层都是“满的”(即每层节点数为 2层号−12^{层号-1});
- 第 hh 层(最底层)的节点从左到右连续排列,中间不能空缺;
- 但最底层的节点不一定是满的,只需要是“尽可能左边连续”。
那么问题是:
一个高度为 8 的完全二叉树,最少有多少个叶子结点?
✅ 正确理解高度为 8:
- 高度为 8,表示有 8 层,最顶层为第 1 层,最底层为第 8 层;
- 叶子结点只能出现在第 7 层或第 8 层;
- 如果第 8 层越少,叶子结点就越少;
- 所以“最少叶子结点”的情形是:第 8 层一个都没有,叶子结点全部出现在第 7 层的末端部分(因为它们没有孩子)。
❗注意:
完全二叉树的最后一层可以不满,所以第 8 层可以没有节点,只要前面满足“完全”的定义就行。
计算:
- 第 7 层有 26=642^6 = 64 个节点;
- 如果第 8 层为空,这 64 个第 7 层节点就是叶子;
- 所以:最少叶子结点数是 64 个。
✅ 结论:
你说的“第八层应该全部有节点”适用于满二叉树,不是完全二叉树。
易错题本
完全二叉树的最大节点数
Q1:已知一棵完全二叉树的第 6层(设根为第1层)有8个叶结点,则该完全二叉树的结点个数最多是
A.39
B.52
C.111
D.119
Q1:对于任意一棵高度为5且有10个结点的二叉树,若采用顺序存储结构保存,每个结点占1个存储单元(仅存放结点的数据信息),则存放该二叉树需要的存储单元数量至少是
A.31
B.16
C.15
D.10
疑问:为什么不能创建一个顺序数据结构来储存信息,这样可以避免空间浪费
高质视频推荐
众所周知,正知识不一定正,但是野知识一定够野
这种应付考试的方法推荐直接掌握如何使用方法,不要浪费时间理解,时间要花在正确的事情上
可视化讲解二叉树的遍历方式
二叉树无脑遍历方式
知二求一【二叉树遍历求解】
这个方法可以帮助求得二叉树的大致构成方式,实际的左右支构成情况还会有多种
森林、树、二叉树的无痛转化
计算特定序列顺序二叉树数量
已知节点数,求不同形态的二叉树数量等于求解该数量下的卡特兰数。
而每种形态对应特定序列的二叉树只有一种。因此计算特定序列顺序二叉树数量等价于求解该数量下的卡特兰数。
五分钟带你学会树的计数问题(卡特兰数、先序序列和中序序列关系、根据先序序列对应不同二叉树)【408 2015真题数据结构2题】
已知节点数和叶节点数,求无右孩子节点数
已知一棵有 2011个结点的树,其叶结点个数为116,该树对应的二叉树中无右孩子的结点个数是 ( )。【2011年全国试题6(2分)】