2023.9.9:
题目:
//编写一个程序读入用户输入的一串先序遍历的字符串
//根据这个字符串创建一个二叉树并以指针的方式存储
//题目示例字符串:ABC##DEG##F###
代码以及注释分析:
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
//这个函数接收一个int类型数组的首元素地址、一个用于记录当前处理位置的指针pi
BTNode* BinaryTreeCreate(BTDataType* a, int* pi)
{
//当程序读到该字符为符号#时,在树中创建空结点NULL
if (a[*pi] == '#')
{
(*pi)++;
return NULL;
}
//在树中开辟一个新的结点,通过malloc函数创建新的空间
//并通过一个if语句来判断malloc是否成功
BTNode* root = (BTNode*)malloc(sizeof(BTNode));
if (root == NULL)
{
perror("malloc fail\n");
return NULL;
}
//将创建好的树(目前只有一个根节点)
//将它的内容设置为字符串的一个字符
root->data = a[*pi];
(*pi)++; //字符串向后走一个字符
//通过递归的方式将下一个字符的地址传入函数
root->left = BinaryTreeCreate(a, pi);
root->right = BinaryTreeCreate(a, pi);
//递归完成时,将创建好的树的根节点地址返回
return root;
}
//通过typedef关键字将定义的二叉树结点
//定义为名称"BTNode"
//每个二叉树结点都拥有一个int类型的“data”数据
//并且拥有相同类型的两个指针(都为BinaryTreeNode类型)
typedef int BTDataType;
typedef struct BinaryTreeNode
{
BTDataType data;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BTNode;
(图中的结点结构体已经通过typedef关键字重新命名为:BTNode)
层序遍历:
复习:有关队列的知识(使用ChatGPT)
队列是一种常见的数据结构,它按照先进先出(FIFO)的原则管理元素。在队列中,新元素被添加到队列的末尾,而从队列中删除元素时,总是从队列的前端进行操作。这样确保了先进入队列的元素先被处理。
队列通常具有以下两个基本操作:
1. 入队(enqueue):将元素添加到队列的末尾。
2. 出队(dequeue):从队列的前端删除并返回元素。
除了基本操作外,队列还具有其他常用的操作,例如:
- 判空(isEmpty):判断队列是否为空。
- 判满(isFull):判断队列是否已满。
- 获取队首元素(front):返回队列的第一个元素,而不删除它。
- 获取队列长度(size):返回队列中元素的数量。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_SIZE 100
// 定义队列结构
typedef struct {
int data[MAX_SIZE];
int front; // 队首索引
int rear; // 队尾索引
} Queue;
// 初始化队列
void initQueue(Queue* queue) {
queue->front = 0;
queue->rear = -1;
}
// 入队
void enqueue(Queue* queue, int item) {
if (queue->rear == MAX_SIZE - 1) {
printf("队列已满,无法入队。\n");
return;
}
queue->rear++;
queue->data[queue->rear] = item;
printf("入队元素:%d\n", item);
}
// 出队
int dequeue(Queue* queue) {
if (queue->rear < queue->front) {
printf("队列为空,无法出队。\n");
return -1;
}
int item = queue->data[queue->front];
queue->front++;
printf("出队元素:%d\n", item);
return item;
}
// 判空
bool isEmpty(Queue* queue) {
return queue->rear < queue->front;
}
// 判满
bool isFull(Queue* queue) {
return queue->rear == MAX_SIZE - 1;
}
// 获取队首元素
int front(Queue* queue) {
if (isEmpty(queue)) {
printf("队列为空。\n");
return -1;
}
return queue->data[queue->front];
}
// 获取队列长度
int size(Queue* queue) {
return queue->rear - queue->front + 1;
}
int main() {
Queue queue;
initQueue(&queue);
enqueue(&queue, 1);
enqueue(&queue, 2);
enqueue(&queue, 3);
printf("队列长度:%d\n", size(&queue));
printf("队首元素:%d\n", front(&queue));
dequeue(&queue);
dequeue(&queue);
printf("队列长度:%d\n", size(&queue));
printf("队首元素:%d\n", front(&queue));
return 0;
}
```
在上面的代码中,使用结构体 `Queue` 定义了一个队列。它包含一个整型数组 `data` 作为队列的存储空间,以及 `front` 和 `rear` 分别表示队首和队尾的索引。
使用 `initQueue` 函数来初始化队列,将 `front` 设为0,`rear` 设为-1。
`enqueue` 函数用于将元素入队。首先检查队列是否已满,如果已满则打印提示信息并返回。否则,将 `rear` 向后移动一位,并将元素存入 `data` 数组中。
`dequeue` 函数用于将元素出队。首先检查队列是否为空,如果为空则打印提示信息并返回-1。否则,返回队首元素,并将 `front` 向后移动一位。
`isEmpty` 函数用于判断队列是否为空,如果 `rear` 小于 `front`,则队列为空。
`isFull` 函数用于判断队列是否已满,如果 `rear` 等于 `MAX_SIZE - 1`,则队列已满。
`front` 函数用于获取队首元素,如果队列为空,则打印提示信息并返回-1。
`size` 函数用于获取队列的长度,计算方法为 `rear - front + 1`。
在主函数中,初始化队列,然后进行一系列的入队和出队操作,并打印队列的长度和队首元素。
另外一种通过队列先进先出实现二叉树销毁的方法:
主要思路:上一层出队列的时候代入子节点,以此遍历整棵树
代码:
判断一棵树是不是完全二叉树:
思路:如果在进行层序遍历的时候遇到了NULL值,但是后面的数值全部都为NULL值,则能说明该树为完全二叉树,如果存在非空数据,说明不是完全二叉树
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
// 定义二叉树节点结构
typedef struct BTNode {
int data;
struct BTNode* left;
struct BTNode* right;
} BTNode;
// 创建新的二叉树节点
BTNode* createNode(int data) {
BTNode* node = malloc(sizeof(BTNode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
// 判断一棵树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root) {
if (root == NULL) {
return true;
}
// 创建队列并初始化
BTNode** queue = malloc(sizeof(BTNode*) * 1000);
int front = 0; // 队首索引
int rear = 0; // 队尾索引
// 将根节点入队
queue[rear++] = root;
// 标记是否遇到过空节点
bool foundNull = false;
while (front < rear) {
BTNode* node = queue[front++];
// 如果遇到空节点,并且后续还有非空节点,说明不是完全二叉树
if (node == NULL) {
foundNull = true;
} else {
// 如果已经遇到过空节点,并且当前节点非空,说明不是完全二叉树
if (foundNull) {
free(queue);
return false;
}
// 将当前节点的左子节点和右子节点入队
queue[rear++] = node->left;
queue[rear++] = node->right;
}
}
free(queue);
return true;
}
int main() {
// 构造示例二叉树
BTNode* root = createNode(1);
root->left = createNode(2);
root->right = createNode(3);
root->left->left = createNode(4);
root->left->right = createNode(5);
root->right->left = createNode(6);
// 判断是否是完全二叉树
bool isComplete = BinaryTreeComplete(root);
// 打印结果
if (isComplete) {
printf("这棵树是完全二叉树\n");
} else {
printf("这棵树不是完全二叉树\n");
}
// 释放内存
free(root->left->left);
free(root->left->right);
free(root->right->left);
free(root->left);
free(root->right);
free(root);
return 0;
}
代码:
深度优先遍历和广度优先遍历:
举例:
DFS:前、中、后序遍历
BFS:层序遍历