当前位置: 首页 > news >正文

数据结构 10 二叉树作业

1 实现二叉树所有节点左右子树交换

#include <stdio.h>
#include <stdlib.h>// 二叉树节点结构定义
struct TreeNode {int data;struct TreeNode* lchild;  // 左子树指针struct TreeNode* rchild;  // 右子树指针
};// 创建新节点
struct TreeNode* createNode(int data) {struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));if (node == NULL) {printf("内存分配失败\n");exit(1);}node->data = data;node->lchild = NULL;node->rchild = NULL;return node;
}// 交换所有节点的左右子树
void swapLeftRight(struct TreeNode* root) {if (root == NULL) {  // 空树直接返回return;}// 交换当前节点的左右子树struct TreeNode* temp = root->lchild;root->lchild = root->rchild;root->rchild = temp;// 递归处理左子树swapLeftRight(root->lchild);// 递归处理右子树swapLeftRight(root->rchild);
}// 前序遍历(用于验证结果)
void preOrder(struct TreeNode* root) {if (root == NULL) {return;}printf("%d ", root->data);preOrder(root->lchild);preOrder(root->rchild);
}// 释放二叉树内存
void freeTree(struct TreeNode* root) {if (root == NULL) {return;}freeTree(root->lchild);freeTree(root->rchild);free(root);
}int main() {// 构建示例二叉树struct TreeNode* root = createNode(1);root->lchild = createNode(2);root->rchild = createNode(3);root->lchild->lchild = createNode(4);root->lchild->rchild = createNode(5);printf("交换前前序遍历:");preOrder(root);printf("\n");// 执行左右子树交换swapLeftRight(root);printf("交换后前序遍历:");preOrder(root);printf("\n");// 释放内存freeTree(root);return 0;
}

代码说明:

  1. 节点结构:使用struct TreeNode定义二叉树节点,包含数据域和左右子树指针。
  2. 创建节点createNode函数负责动态分配节点内存并初始化。
  3. 交换逻辑swapLeftRight函数通过递归实现:
    • 先交换当前节点的左右子树
    • 再递归交换左子树和右子树
  4. 验证方式:通过前序遍历输出交换前后的节点序列,直观展示交换效果。
  5. 内存管理freeTree函数递归释放所有节点内存,避免内存泄漏。

运行结果:

对于示例树:

    1/ \2   3/ \
4   5

输出为:

交换前前序遍历:1 2 4 5 3 
交换后前序遍历:1 3 2 5 4 

时间复杂度为O(n)(每个节点处理一次),空间复杂度为O(h)h为树的高度,递归栈深度)。

2 使用队列来实现二叉树的层次遍历,同时统计度为 1 的结点数目

算法思路

  1. 层次遍历:借助队列,从根节点开始,依次将节点入队,然后出队并处理,同时将其左右子节点入队(若存在)。
  2. 统计度为 1 的结点:对于每个出队的节点,判断其左、右子节点的存在情况
    • 若只有左子节点或只有右子节点,则该节点的度为 1,计数加 1。

C 语言实现代码

#include <stdio.h>
#include <stdlib.h>// 二叉树结点结构
typedef struct TreeNode {int data;struct TreeNode *lchild, *rchild;
} TreeNode;// 队列结点结构
typedef struct QueueNode {TreeNode *treeNode;struct QueueNode *next;
} QueueNode;// 队列结构
typedef struct {QueueNode *front, *rear;
} Queue;// 初始化队列
void initQueue(Queue *q) {q->front = q->rear = NULL;
}// 入队操作
void enQueue(Queue *q, TreeNode *node) {QueueNode *newNode = (QueueNode *)malloc(sizeof(QueueNode));newNode->treeNode = node;newNode->next = NULL;if (q->rear == NULL) {q->front = q->rear = newNode;} else {q->rear->next = newNode;q->rear = newNode;}
}// 出队操作
TreeNode* deQueue(Queue *q) {if (q->front == NULL) return NULL;QueueNode *temp = q->front;TreeNode *node = temp->treeNode;q->front = q->front->next;if (q->front == NULL) q->rear = NULL;free(temp);return node;
}// 统计度为1的结点数目
int countDegree1Nodes(TreeNode *root) {if (root == NULL) return 0;Queue q;initQueue(&q);enQueue(&q, root);int count = 0;while (q.front != NULL) {TreeNode *node = deQueue(&q);// 判断结点的度是否为1if ((node->lchild != NULL && node->rchild == NULL) || (node->lchild == NULL && node->rchild != NULL)) {count++;}if (node->lchild != NULL) enQueue(&q, node->lchild);if (node->rchild != NULL) enQueue(&q, node->rchild);}return count;
}// 创建二叉树结点(示例用)
TreeNode* createNode(int data) {TreeNode *node = (TreeNode *)malloc(sizeof(TreeNode));node->data = data;node->lchild = node->rchild = NULL;return node;
}// 主函数示例
int main() {// 构建示例二叉树TreeNode *root = createNode(1);root->lchild = createNode(2);root->rchild = createNode(3);root->lchild->lchild = createNode(4);root->rchild->lchild = createNode(5);root->rchild->rchild = createNode(6);root->rchild->lchild->lchild = createNode(7);int result = countDegree1Nodes(root);printf("度为1的结点数目:%d\n", result);return 0;
}

代码说明

  • 队列操作initQueue初始化队列,enQueue实现节点入队,deQueue实现节点出队,用于层次遍历的顺序控制。
  • 统计逻辑:在层次遍历过程中,对每个节点判断其左、右子节点的存在情况,若只有一个子节点则计数加 1。
  • 时间复杂度:\(O(n)\)(n为二叉树结点数,每个结点入队、出队各一次)。
  • 空间复杂度:\(O(n)\)(队列最多存储一层的结点,最坏情况下为满二叉树的最后一层,结点数约为\(n/2\))。

算法思路

  1. 层次遍历:利用队列(std::queue)实现二叉树的层次遍历,按层访问每个节点。
  2. 统计度为 1 的节点:对每个节点,判断其左、右子节点的存在情况:
    • 若仅存在左子节点或仅存在右子节点,则该节点的度为 1,计数加 1。

C++ 代码实现

#include <iostream>
#include <queue>  // 用于队列操作
using namespace std;// 二叉树节点结构
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};// 统计度为1的节点数量
int countDegree1Nodes(TreeNode* root) {if (root == nullptr) {return 0;  // 空树,直接返回0}queue<TreeNode*> q;  // 队列用于层次遍历q.push(root);        // 根节点入队int count = 0;       // 计数变量while (!q.empty()) {TreeNode* curr = q.front();  // 取出队头节点q.pop();// 判断当前节点的度是否为1(仅左或仅右子节点存在)bool hasLeft = (curr->left != nullptr);bool hasRight = (curr->right != nullptr);if (hasLeft != hasRight) {  // 异或:一个存在,一个不存在count++;}// 左右子节点入队(若存在)if (hasLeft) {q.push(curr->left);}if (hasRight) {q.push(curr->right);}}return count;
}// 构建示例二叉树(用于测试)
TreeNode* buildExampleTree() {// 构建如下二叉树://       1//      / \//     2   3//    /   / \//   4   5   6//      ///     7TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);  // 节点2的左子节点root->right->left = new TreeNode(5); // 节点3的左子节点root->right->right = new TreeNode(6);// 节点3的右子节点root->right->left->left = new TreeNode(7); // 节点5的左子节点return root;
}// 释放二叉树内存
void freeTree(TreeNode* root) {if (root == nullptr) return;freeTree(root->left);freeTree(root->right);delete root;
}int main() {TreeNode* root = buildExampleTree();int result = countDegree1Nodes(root);cout << "度为1的节点数量:" << result << endl;  // 示例中结果为2(节点2和节点5)freeTree(root);  // 释放内存,避免泄漏return 0;
}

代码说明

  1. 节点结构TreeNode包含值val和左右子节点指针leftright,构造函数初始化节点。
  2. 层次遍历:使用std::queue存储节点,通过push(入队)和pop(出队)操作实现按层访问。
  3. 统计逻辑:对每个节点,通过判断leftright是否存在(异或逻辑),确定其度是否为 1,若满足则计数加 1。
  4. 内存管理freeTree函数递归释放所有节点内存,避免内存泄漏。

运行结果

对于示例二叉树,度为 1 的节点是节点 2(仅有左子节点 4)和节点 5(仅有左子节点 7),因此输出:

度为1的节点数量:2

复杂度分析

  • 时间复杂度:(O(n)),其中n为二叉树节点总数,每个节点仅被访问一次。
  • 空间复杂度:(O(m)),其中m为二叉树中某一层的最大节点数(队列的最大存储量),最坏情况下为满二叉树的最后一层(约(n/2)个节点)。

3 计算二叉树的深度

cpp

要计算二叉树的深度,可以采用递归层次遍历的方法,以下分别给出两种实现:

方法一:递归法

思路:二叉树的深度 = max (左子树深度,右子树深度) + 1(根节点自身深度)。

  • 空树深度为 0;
  • 叶子节点深度为 1。
#include <iostream>
using namespace std;// 二叉树节点结构
struct TreeNode {int data;TreeNode* left;TreeNode* right;TreeNode(int d) : data(d), left(nullptr), right(nullptr) {}
};// 递归求二叉树深度
int getDepth(TreeNode* root) {if (root == nullptr) {return 0; // 空树深度为0}// 左子树深度int leftDepth = getDepth(root->left);// 右子树深度int rightDepth = getDepth(root->right);// 返回较大深度 + 1(根节点)return max(leftDepth, rightDepth) + 1;
}// 测试示例
int main() {// 构建二叉树://     1//    / \//   2   3//  / \// 4   5TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);cout << "二叉树深度:" << getDepth(root) << endl; // 输出3return 0;
}

方法二:层次遍历(迭代法)

思路:通过队列按层遍历二叉树,每遍历完一层,深度加 1。

#include <iostream>
#include <queue>
using namespace std;struct TreeNode {int data;TreeNode* left;TreeNode* right;TreeNode(int d) : data(d), left(nullptr), right(nullptr) {}
};// 层次遍历求二叉树深度
int getDepth(TreeNode* root) {if (root == nullptr) {return 0;}queue<TreeNode*> q;q.push(root);int depth = 0;while (!q.empty()) {int levelSize = q.size(); // 当前层的节点数depth++; // 遍历完一层,深度加1for (int i = 0; i < levelSize; i++) {TreeNode* node = q.front();q.pop();if (node->left) q.push(node->left);if (node->right) q.push(node->right);}}return depth;
}// 测试示例(同递归法)
int main() {TreeNode* root = new TreeNode(1);root->left = new TreeNode(2);root->right = new TreeNode(3);root->left->left = new TreeNode(4);root->left->right = new TreeNode(5);cout << "二叉树深度:" << getDepth(root) << endl; // 输出3return 0;
}

复杂度分析

  • 递归法
    • 时间复杂度:(O(n))(每个节点仅访问一次)。
    • 空间复杂度:(O(h))(h为树的高度,递归栈的深度)。
  • 层次遍历法
    • 时间复杂度:(O(n))(每个节点入队、出队一次)。
    • 空间复杂度:(O(n))(队列最多存储一层的节点,最坏情况为满二叉树的最后一层)。

两种方法均可高效求解二叉树深度,递归法代码更简洁,层次遍历法更直观易理解。

c

方法一:递归法

思路:二叉树的深度 = 左右子树深度的最大值 + 1(根节点自身)。

  • 空树深度为 0;
  • 递归计算左、右子树深度,取最大值加 1 即为当前树的深度。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>  // 用于max函数(需链接数学库,编译时加-lm)// 二叉树节点结构
struct TreeNode {int data;struct TreeNode* left;struct TreeNode* right;
};// 创建节点
struct TreeNode* createNode(int data) {struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));if (node == NULL) {printf("内存分配失败\n");exit(1);}node->data = data;node->left = NULL;node->right = NULL;return node;
}// 递归求二叉树深度
int getDepth(struct TreeNode* root) {if (root == NULL) {return 0;  // 空树深度为0}// 计算左子树深度int leftDepth = getDepth(root->left);// 计算右子树深度int rightDepth = getDepth(root->right);// 返回较大深度 + 1(当前节点)return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;
}// 释放二叉树内存
void freeTree(struct TreeNode* root) {if (root == NULL) return;freeTree(root->left);freeTree(root->right);free(root);
}int main() {// 构建示例二叉树://     1//    / \//   2   3//  / \// 4   5struct TreeNode* root = createNode(1);root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5);printf("二叉树深度:%d\n", getDepth(root));  // 输出3freeTree(root);return 0;
}

方法二:层次遍历法(迭代法)

思路:通过队列按层遍历二叉树,每遍历完一层,深度加 1。

  • 队列存储当前层的所有节点;
  • 记录每层节点数量,遍历完该层后深度加 1,再将下一层节点入队。
#include <stdio.h>
#include <stdlib.h>// 二叉树节点结构
struct TreeNode {int data;struct TreeNode* left;struct TreeNode* right;
};// 队列节点结构(用于层次遍历)
struct QueueNode {struct TreeNode* treeNode;struct QueueNode* next;
};// 队列结构
struct Queue {struct QueueNode* front;  // 队头struct QueueNode* rear;   // 队尾
};// 创建二叉树节点
struct TreeNode* createNode(int data) {struct TreeNode* node = (struct TreeNode*)malloc(sizeof(struct TreeNode));if (node == NULL) {printf("内存分配失败\n");exit(1);}node->data = data;node->left = node->right = NULL;return node;
}// 初始化队列
void initQueue(struct Queue* q) {q->front = q->rear = NULL;
}// 入队操作
void enQueue(struct Queue* q, struct TreeNode* node) {struct QueueNode* newNode = (struct QueueNode*)malloc(sizeof(struct QueueNode));newNode->treeNode = node;newNode->next = NULL;if (q->rear == NULL) {  // 队列空时,队头队尾指向新节点q->front = q->rear = newNode;} else {q->rear->next = newNode;q->rear = newNode;}
}// 出队操作
struct TreeNode* deQueue(struct Queue* q) {if (q->front == NULL) return NULL;  // 队列为空struct QueueNode* temp = q->front;struct TreeNode* node = temp->treeNode;q->front = q->front->next;if (q->front == NULL) {  // 队列为空时,队尾置空q->rear = NULL;}free(temp);return node;
}// 层次遍历求二叉树深度
int getDepth(struct TreeNode* root) {if (root == NULL) return 0;  // 空树深度为0struct Queue q;initQueue(&q);enQueue(&q, root);int depth = 0;while (q.front != NULL) {int levelSize = 0;  // 当前层的节点数struct QueueNode* curr = q.front;// 统计当前层的节点数while (curr != NULL) {levelSize++;curr = curr->next;}// 遍历当前层所有节点,并将下一层节点入队for (int i = 0; i < levelSize; i++) {struct TreeNode* node = deQueue(&q);if (node->left != NULL) enQueue(&q, node->left);if (node->right != NULL) enQueue(&q, node->right);}depth++;  // 遍历完一层,深度加1}return depth;
}// 释放二叉树内存
void freeTree(struct TreeNode* root) {if (root == NULL) return;freeTree(root->left);freeTree(root->right);free(root);
}int main() {// 构建与递归法相同的示例二叉树struct TreeNode* root = createNode(1);root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5);printf("二叉树深度:%d\n", getDepth(root));  // 输出3freeTree(root);return 0;
}

两种方法对比

方法时间复杂度空间复杂度特点
递归法\(O(n)\)\(O(h)\)(h 为树高)代码简洁,依赖递归栈
层次遍历法\(O(n)\)\(O(m)\)(m 为层最大节点数)非递归,需手动实现队列

说明

  • 递归法通过函数调用栈隐式处理节点访问顺序,代码更简洁,但对于深度极大的树可能导致栈溢出。
  • 层次遍历法通过显式队列控制节点访问,逻辑更直观,避免了递归栈溢出风险,适合大规模树。
  • 两种方法均需遍历所有节点,时间复杂度均为 \(O(n)\)(n 为节点总数)。

4 先序线索化

核心前提:先序遍历与线索化规则

  1. 先序遍历顺序:根节点 → 左子树 → 右子树(空树直接返回)。
  2. 线索化规则
    • 节点的左指针:若左子树为空,就指向它的「先序前驱」(遍历顺序中前一个节点);若左子树存在,正常指向左子节点。
    • 节点的右指针:若右子树为空,就指向它的「先序后继」(遍历顺序中后一个节点);若右子树存在,正常指向右子节点。
    • 只有整棵树的「最后一个遍历节点」,右指针没有后继,才会保留为空。

举例:左子树为空的二叉树

假设二叉树结构(左子树全空):

    A(根)\B\C(叶子)
  1. 先序遍历顺序:A → B → C(因为左子树都为空,直接走右子树)。
  2. 逐个分析节点的指针
    • 节点 A:左子树为空 → 左指针指向「先序前驱」(A 是第一个节点,无前驱,按规则左指针仍为空?不!线索化会强制利用空指针,此时 A 的左指针虽无前驱,但右子树存在(指向 B),所以右指针正常。
    • 节点 B:左子树为空 → 左指针指向「先序前驱」(A);右子树存在(指向 C),右指针正常。
    • 节点 C:左子树为空 → 左指针指向「先序前驱」(B);右子树为空 → 右指针指向「先序后继」(C 是最后一个节点,无后继),所以右指针保留为空。
  3. 空链域统计:只有节点 C 的右指针是空的,共 1 个。

结论

左子树为空的二叉树,先序线索化后,空链域个数为 1,对应选项 C。

5 判断二叉树类型

答案:C

解析

  • 先序遍历顺序是 “根 - 左 - 右”,后序遍历顺序是 “左 - 右 - 根”。
  • 若先序和后序序列正好相反,说明二叉树的结构是一条单链(每个节点只有一个子节点)。
  • 这种结构中,只有一个叶子节点(最底层的那个节点)。
  • 选项 A(均无左孩子)或 B(均无右孩子)只是单链的两种特殊情况,不能涵盖所有可能;选项 D(任意二叉树)显然不成立。

以 “全右链” 为例,结构如下:

  A\B\C\D(叶子节点)
  • 先序遍历:A → B → C → D
  • 后序遍历:D → C → B → A两者完全相反,且只有 D 一个叶子节点。

同理 “全左链” 结构,先序和后序也会完全相反,且只有最底层的节点是叶子。所以这种二叉树的核心特征是只有一个叶子节点,结构退化为单链(类似链表)。

6 树的存储形式

答案:D

解析

  • 选项 A(双亲表示法):通过记录每个节点的双亲节点来存储树,是树的常见存储形式。
  • 选项 B(孩子链表表示法):为每个节点维护一个孩子链表,存储其所有子节点,是树的存储形式。
  • 选项 C(孩子兄弟表示法):将树转换为二叉树的形式存储(左孩子表示第一个子节点,右兄弟表示下一个兄弟节点),可用于树的存储。
  • 选项 D(顺序存储表示法):树的结构不规则,难以用纯顺序存储准确表达节点间的层次和父子关系,不是树的常规存储形式。

7 后根遍历序列

答案:B

解析:树转换为二叉树时,采用 “孩子 - 兄弟” 表示法(左孩子为原树的第一个子节点,右兄弟为原树的下一个兄弟节点)。树的后根遍历顺序是 “先遍历所有子树,再访问根节点”;而该二叉树的中序遍历顺序与之完全一致,因此树的后根遍历序列等同于其对应二叉树的中序序列。

8 完全二叉树的深度

http://www.dtcms.com/a/562138.html

相关文章:

  • 网站建设视频教程 百度云如何做网站赚钱6
  • HTML5 测验
  • 沧州网站建设王宝祥wordpress能恢复修改前吗
  • 有没有专门做京东天猫的人才网站e4a能建设网站吗
  • Java记录类:简化数据载体的新选择
  • 郑州做网站开发销售潍坊做网站
  • C++—string(1):string类的学习与使用
  • 做一张网站专栏背景图网页设计模板网站
  • 关于企业网站建设的市场比质比价调查报告手机制作ppt的软件免费
  • 做外贸网站可以收付款吗电商网站建站
  • 响水专业做网站手机wap网站怎么做
  • 催收网站开发要看网的域名是多少
  • 怎么用ps做网站幻灯片做一个app的成本
  • 河南省台前县建设局网站织梦小说网站源码
  • 在线免费视频网站推广安卓小程序开发入门
  • 网站维护电话站长统计代码
  • 数学分析简明教程——2.3 (未完)
  • 计网5.3.3 TCP连接管理
  • 云南哪几个建网站公司甘肃做网站多少钱
  • verilog 中函数和任务的区别,举例说明
  • 网页制作与网站建设实战大全 pdf有名的软件开发公司
  • asyncio.get_running_loop() vs asyncio.get_event_loop() 作用与区别
  • 网站建设公司怎么挖掘客户房产网站建设方案论文
  • 美丽南方的网站建设资讯网站的好处
  • X-anylabelIng运行自动标注报错cannot import name ‘_C‘ from ‘sam2‘解决
  • 建网站申请长春 网站建设网络推广网页设计
  • ARM 总线技术 —— APB
  • 中文网站常用字体wordpress添加一言
  • uehtml 网站源码国家林业工程建设协会网站
  • 网站建设的软硬件平台百姓网全国免费发布信息