1 实现二叉树所有节点左右子树交换
#include
#include
// 二叉树节点结构定义
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;
}
代码说明:
- 节点结构:使用
struct TreeNode定义二叉树节点,包含数据域和左右子树指针。 - 创建节点:
createNode函数负责动态分配节点内存并初始化。 - 交换逻辑:
swapLeftRight函数通过递归实现:- 先交换当前节点的左右子树
- 再递归交换左子树和右子树
- 验证方式:通过前序遍历输出交换前后的节点序列,直观展示交换效果。
- 内存管理:
freeTree函数递归释放所有节点内存,避免内存泄漏。
运行结果:
对于示例树:
1
/ \
2 3
/ \
4 5
输出为:
交换前前序遍历:1 2 4 5 3
交换后前序遍历:1 3 2 5 4
时间复杂度为O(n)(每个节点处理一次),空间复杂度为O(h)(h为树的高度,递归栈深度)。
2 使用队列来实现二叉树的层次遍历,同时统计度为 1 的结点数目
算法思路
- 层次遍历:借助队列,从根节点开始,依次将节点入队,然后出队并处理,同时将其左右子节点入队(若存在)。
- 统计度为 1 的结点:对于每个出队的节点,判断其左、右子节点的存在情况:
- 若只有左子节点或只有右子节点,则该节点的度为 1,计数加 1。
C 语言实现代码
#include
#include
// 二叉树结点结构
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);
// 判断结点的度是否为1
if ((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\))。
算法思路
- 层次遍历:利用队列(
std::queue)实现二叉树的层次遍历,按层访问每个节点。 - 统计度为 1 的节点:对每个节点,判断其左、右子节点的存在情况:
- 若仅存在左子节点或仅存在右子节点,则该节点的度为 1,计数加 1。
C++ 代码实现
#include
#include // 用于队列操作
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 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
// /
// 7
TreeNode* 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;
}
代码说明
- 节点结构:
TreeNode包含值val和左右子节点指针left、right,构造函数初始化节点。 - 层次遍历:使用
std::queue存储节点,通过push(入队)和pop(出队)操作实现按层访问。 - 统计逻辑:对每个节点,通过判断
left和right是否存在(异或逻辑),确定其度是否为 1,若满足则计数加 1。 - 内存管理:
freeTree函数递归释放所有节点内存,避免内存泄漏。
运行结果
对于示例二叉树,度为 1 的节点是节点 2(仅有左子节点 4)和节点 5(仅有左子节点 7),因此输出:
度为1的节点数量:2
复杂度分析
- 时间复杂度:(O(n)),其中n为二叉树节点总数,每个节点仅被访问一次。
- 空间复杂度:(O(m)),其中m为二叉树中某一层的最大节点数(队列的最大存储量),最坏情况下为满二叉树的最后一层(约(n/2)个节点)。
3 计算二叉树的深度
cpp
要计算二叉树的深度,可以采用递归或层次遍历的方法,以下分别给出两种实现:
方法一:递归法
思路:二叉树的深度 = max (左子树深度,右子树深度) + 1(根节点自身深度)。
- 空树深度为 0;
- 叶子节点深度为 1。
#include
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 5
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; // 输出3
return 0;
}
方法二:层次遍历(迭代法)
思路:通过队列按层遍历二叉树,每遍历完一层,深度加 1。
#include
#include
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 q;
q.push(root);
int depth = 0;
while (!q.empty()) {
int levelSize = q.size(); // 当前层的节点数
depth++; // 遍历完一层,深度加1
for (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; // 输出3
return 0;
}
复杂度分析
- 递归法:
- 时间复杂度:(O(n))(每个节点仅访问一次)。
- 空间复杂度:(O(h))(h为树的高度,递归栈的深度)。
- 层次遍历法:
- 时间复杂度:(O(n))(每个节点入队、出队一次)。
- 空间复杂度:(O(n))(队列最多存储一层的节点,最坏情况为满二叉树的最后一层)。
两种方法均可高效求解二叉树深度,递归法代码更简洁,层次遍历法更直观易理解。
c
方法一:递归法
思路:二叉树的深度 = 左右子树深度的最大值 + 1(根节点自身)。
- 空树深度为 0;
- 递归计算左、右子树深度,取最大值加 1 即为当前树的深度。
#include
#include
#include // 用于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 5
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)); // 输出3
freeTree(root);
return 0;
}
方法二:层次遍历法(迭代法)
思路:通过队列按层遍历二叉树,每遍历完一层,深度加 1。
- 队列存储当前层的所有节点;
- 记录每层节点数量,遍历完该层后深度加 1,再将下一层节点入队。
#include
#include
// 二叉树节点结构
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; // 空树深度为0
struct 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)); // 输出3
freeTree(root);
return 0;
}
两种方法对比
| 方法 | 时间复杂度 | 空间复杂度 | 特点 |
|---|---|---|---|
| 递归法 | \(O(n)\) | \(O(h)\)(h 为树高) | 代码简洁,依赖递归栈 |
| 层次遍历法 | \(O(n)\) | \(O(m)\)(m 为层最大节点数) | 非递归,需手动实现队列 |
说明
- 递归法通过函数调用栈隐式处理节点访问顺序,代码更简洁,但对于深度极大的树可能导致栈溢出。
- 层次遍历法通过显式队列控制节点访问,逻辑更直观,避免了递归栈溢出风险,适合大规模树。
- 两种方法均需遍历所有节点,时间复杂度均为 \(O(n)\)(n 为节点总数)。
4 先序线索化

核心前提:先序遍历与线索化规则
- 先序遍历顺序:根节点 → 左子树 → 右子树(空树直接返回)。
- 线索化规则:
- 节点的左指针:若左子树为空,就指向它的「先序前驱」(遍历顺序中前一个节点);若左子树存在,正常指向左子节点。
- 节点的右指针:若右子树为空,就指向它的「先序后继」(遍历顺序中后一个节点);若右子树存在,正常指向右子节点。
- 只有整棵树的「最后一个遍历节点」,右指针没有后继,才会保留为空。
举例:左子树为空的二叉树
假设二叉树结构(左子树全空):
A(根)
\
B
\
C(叶子)
- 先序遍历顺序:A → B → C(因为左子树都为空,直接走右子树)。
- 逐个分析节点的指针:
- 节点 A:左子树为空 → 左指针指向「先序前驱」(A 是第一个节点,无前驱,按规则左指针仍为空?不!线索化会强制利用空指针,此时 A 的左指针虽无前驱,但右子树存在(指向 B),所以右指针正常。
- 节点 B:左子树为空 → 左指针指向「先序前驱」(A);右子树存在(指向 C),右指针正常。
- 节点 C:左子树为空 → 左指针指向「先序前驱」(B);右子树为空 → 右指针指向「先序后继」(C 是最后一个节点,无后继),所以右指针保留为空。
- 空链域统计:只有节点 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 完全二叉树的深度
![]()
浙公网安备 33010602011771号