4、二叉树的前序遍历<难度系数⭐>
📝 题述:给你二叉树的根节点 root ,返回它节点值的前序遍历。
💨 示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
💨 示例 2:
输入:root = []
输出:[]
💨 示例 3:
输入:root = [1]
输出:[1]
💨 示例 4:
输入:root = [1,2]
输出:[1,2]
💨 示例 5:
输入:root = [1,null,2]
输出:[1,2]
⚠ 注意:
1️⃣ 树中节点数目在范围 [0, 100] 内
2️⃣ -100 <= Node.val <= 100
🧷 平台:Visual studio 2017 && windows
🔑 核心思想:先实现 TreeSize 计算出二叉树的节点个数给 returnSize,并开辟好 returnSize 个 int 类型大小的数组。再调用子函数进行前序递归:如果每层函数栈帧中节点为空则结束栈帧,否则把节点放到数组里,并继续递归
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef int BTDataType; typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }BTNode; //malloc空间 BTNode* BuyNode(BTDataType x) { BTNode* node = malloc(sizeof(BTNode)); node->val = x; node->left = NULL; node->right = NULL; return node; } //创建树 BTNode* CreatBinaryTree() { BTNode* node1 = BuyNode(1); BTNode* node2 = BuyNode(2); BTNode* node3 = BuyNode(3); node1->right = node2; node2->left = node3; return node1; } //求二叉树节点的个数 int TreeSize(struct TreeNode* root) { if (root == NULL) { return 0; } return TreeSize(root->left) + TreeSize(root->right) + 1; } //子函数用于递归 - 使用前序的方式 void _preorderTraversal(struct TreeNode* root, int* arr, int* pi) { if (root == NULL) return; //放节点 arr[(*pi)++] = root->val; _preorderTraversal(root->left, arr, pi); _preorderTraversal(root->right, arr, pi); } //Note: The returned array must be malloced, assume caller calls free(). //二叉树的前序遍厉 int* preorderTraversal(struct TreeNode* root, int* returnSize) { //*returnSize用于接收二叉树的节点个数 *returnSize = TreeSize(root); //开辟*returnSize个int类型大小的空间 int* arr = (struct TreeSize*)malloc(sizeof(int)* *returnSize); //因为preorderTraversal不适合递归,所以需要一个子函数;这里每一次递归都是一层函数栈帧,所以对于i来说想要保留正确的下标就要传地址 int i = 0; _preorderTraversal(root, arr, &i); return arr; } int main() { int returnSize = 0; BTNode* root = CreatBinaryTree(); int* arr = preorderTraversal(root, &returnSize); return 0; }
5、二叉树中序遍历<难度系数⭐>
📝 题述:给定一个二叉树的根节点 root ,返回它的中序遍历。
💨 示例 1:
输入:root = [1,null,2,3]
输出:[1,2,3]
💨 示例 2:
输入:root = []
输出:[]
💨 示例 3:
输入:root = [1]
输出:[1]
💨 示例 4:
输入:root = [1,2]
输出:[1,2]
💨 示例 5:
输入:root = [1,null,2]
输出:[1,2]
⚠ 注意:
1️⃣ 树中节点数目在范围 [0, 100] 内
2️⃣ -100 <= Node.val <= 100
🧷 平台:Visual studio 2017 && windows
🔑 核心思想:类似前序
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef int BTDataType; typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }BTNode; //malloc空间 BTNode* BuyNode(BTDataType x) { BTNode* node = malloc(sizeof(BTNode)); node->val = x; node->left = NULL; node->right = NULL; return node; } //创建树 BTNode* CreatBinaryTree() { BTNode* node1 = BuyNode(1); BTNode* node2 = BuyNode(2); BTNode* node3 = BuyNode(3); node1->right = node2; node2->left = node3; return node1; } //求二叉树节点的个数 int TreeSize(struct TreeNode* root) { if (root == NULL) { return 0; } return TreeSize(root->left) + TreeSize(root->right) + 1; } //子函数用于递归 - 使用中序的方式 void _inorderTraversal(struct TreeNode* root, int* arr, int* pi) { if(root == NULL) return; _inorderTraversal(root->left, arr, pi); arr[(*pi)++] = root->val; _inorderTraversal(root->right, arr, pi); } //Note: The returned array must be malloced, assume caller calls free(). //二叉树的中序遍厉 int* inorderTraversal(struct TreeNode* root, int* returnSize){ //*returnSize接收二叉树的节点个数 *returnSize = TreeSize(root); //开辟*returnSize个int类型大小的空间 int* arr = (struct TreeNode*)malloc(sizeof(int)* * returnSize); //递归调用子函数 int i = 0; _inorderTraversal(root, arr, &i); return arr; } int main() { int returnSize = 0; BTNode* root = CreatBinaryTree(); int* arr = inorderTraversal(root, &returnSize); return 0; }
6、二叉树的后序遍历<难度系数⭐>
📝 题述:给定一个二叉树,返回它的后序遍历。
💨 示例 :
输入: [1,null,2,3]
输出: [3,2,1]
🧷 平台:Visual studio 2017 && windows
🔑 核心思想:类似前序
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef int BTDataType; typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }BTNode; //malloc空间 BTNode* BuyNode(BTDataType x) { BTNode* node = malloc(sizeof(BTNode)); node->val = x; node->left = NULL; node->right = NULL; return node; } //创建树 BTNode* CreatBinaryTree() { BTNode* node1 = BuyNode(1); BTNode* node2 = BuyNode(2); BTNode* node3 = BuyNode(3); node1->right = node2; node2->left = node3; return node1; } //求二叉树节点的个数 int TreeSize(struct TreeNode* root) { if (root == NULL) { return 0; } return TreeSize(root->left) + TreeSize(root->right) + 1; } //子函数用于递归 - 使用后序的方式 void _postorderTraversal(struct TreeNode* root, int* arr, int* pi) { if (root == NULL) return; _postorderTraversal(root->left, arr, pi); _postorderTraversal(root->right, arr, pi); arr[(*pi)++] = root->val; } //Note: The returned array must be malloced, assume caller calls free(). //二叉树的后序遍历 int* postorderTraversal(struct TreeNode* root, int* returnSize) { //*returnSize接收二叉树的节点个数 *returnSize = TreeSize(root); //开辟*returnSize个int类型大小的空间 int* arr = (struct TreeNode*)malloc(sizeof(int)* * returnSize); //递归调用子函数 int i = 0; _postorderTraversal(root, arr, &i); return arr; } int main() { int returnSize = 0; BTNode* root = CreatBinaryTree(); int* arr = postorderTraversal(root, &returnSize); return 0; }
7、另一颗树的子树<难度系数⭐>
📝 题述:给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
💨 示例 1:
输入:root = [3,4,5,1,2], subRoot = [4,1,2]
输出:true
💨 示例 2:
输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false
⚠ 注意:
1️⃣ root 树上的节点数量范围是 [1, 2000]
2️⃣ subRoot 树上的节点数量范围是 [1, 1000]
3️⃣ -104 <= root.val <= 104
4️⃣ -104 <= subRoot.val <= 104
🧷 平台:Visual studio 2017 && windows
🔑 核心思想:每一层函数栈帧中都包括:如果 root 等于空,返回 false;如果调用相同的树为真,返回 true;否则继续递归
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<stdbool.h> typedef int BTDataType; typedef struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; }BTNode; //malloc空间 BTNode* BuyNode(BTDataType x) { BTNode* node = malloc(sizeof(BTNode)); node->val = x; node->left = NULL; node->right = NULL; return node; } //创建树1 BTNode* CreatBinaryTree1() { BTNode* node1 = BuyNode(3); BTNode* node2 = BuyNode(4); BTNode* node3 = BuyNode(5); BTNode* node4 = BuyNode(1); BTNode* node5 = BuyNode(2); node1->left = node2; node1->right = node3; node2->left = node4; node2->right = node5; return node1; } //创建树2 BTNode* CreatBinaryTree2() { BTNode* node1 = BuyNode(4); BTNode* node2 = BuyNode(1); BTNode* node3 = BuyNode(2); node1->left = node2; node1->right = node3; return node1; } //相同的树 bool isSameTree(struct TreeNode* p, struct TreeNode* q) { //p为空,q也为空 if (p == NULL && q == NULL) return true; //p和q只有1个为空 if (p == NULL || q == NULL) return false; //p和q的val不等 if (p->val != q->val) return false; //相等递归 return isSameTree(p->left, q->left) && isSameTree(p->right, q->right); } //另一棵树的子树 bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot) { //root等于空 if (root == NULL) return false; //调用相同的树 if (isSameTree(root, subRoot)) return true; //继续递归 return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); } int main() { BTNode* root1 = CreatBinaryTree1(); BTNode* root2 = CreatBinaryTree2(); printf("%d\n", isSubtree(root1, root2)); return 0; }
8、二叉树的构建及遍历<难度系数⭐>
📝 题述:编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
输入描述:
输入包括1行字符串,长度不超过 100。
输出描述:
可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个
空格。 每个输出结果占一行。
💨 示例 :
输入:abc##de#g##f###
输出:c b e g d f a
🧷 平台:Visual studio 2017 && windows
🔑 核心思想:
❗ 注意此题不同于上面的几道接口题,这里是 I/O 类型的题需要我们自己创建树 ❕
根据题意中先序遍历的字符串可以得到:
先前序构建树,再中序输出树
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> struct TreeNode { char val; struct TreeNode* left; struct TreeNode* right; }; //前序构建树 struct TreeNode* CreatTree(char* str, int* pi) { if (str[*pi] == '#') { //空树数组的下标也要++,且为它malloc空间 (*pi)++; return NULL; } //malloc空间 struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); //前序递归 root->val = str[(*pi)++]; root->left = CreatTree(str, pi); root->right = CreatTree(str, pi); return root; } //中序输出树 void InOrder(struct TreeNode* root) { if (root == NULL) return; InOrder(root->left); printf("%c ", root->val); InOrder(root->right); } int main() { char str[100]; scanf("%s", str); int i = 0; struct TreeNode* root = CreatTree(str, &i); InOrder(root); return 0; }
💦 二叉树的创建和销毁
//二叉树创建 BTNode* BinaryCreatBinaryTree(); // 二叉树销毁 void BinaryTreeDestroy(BTNode* root);
❗ BinaryCreatBinaryTree && BinaryTreeDestroy ❕
注意对于 BinaryTreeDestroy 使用后序的方式销毁
#include<stdio.h> #include<stdlib.h> typedef int BTDataType; typedef struct BinaryTreeNode { BTDataType _data; struct BinaryTreeNode* _left; struct BinaryTreeNode* _right; }BTNode; BTNode* BuyNode(BTDataType x) { BTNode* node = malloc(sizeof(BTNode)); node->_data = x; node->_left = NULL; node->_right = NULL; return node; } //创建二叉树 BTNode* BinaryCreatBinaryTree() { BTNode* node1 = BuyNode(1); BTNode* node2 = BuyNode(2); BTNode* node3 = BuyNode(3); BTNode* node4 = BuyNode(4); BTNode* node5 = BuyNode(5); BTNode* node6 = BuyNode(6); node1->_left = node2; node1->_right = node3; node2->_left = node4; node3->_left = node5; node3->_right = node6; return node1; } //后序销毁二叉树 void BinaryTreeDestroy(BTNode* root) { if (root == NULL) return; BinaryTreeDestroy(root->_left); BinaryTreeDestroy(root->_right); free(root); } int main() { BTNode* root = BinaryCreatBinaryTree(); BinaryTreeDestroy(root); root = NULL; return 0; }
💦 二叉树的层序遍厉
//层序遍厉 void BinaryTreeLeveOrder(BTNode* root); //判断二叉树是否是完全二叉树 bool BinaryTreeComplete(BTNode* root);
BinaryTreeLeveOrder:
🔑 核心思想 🔑
使用队列的方式:先入第一层,出上一层,再入下一层 … …
需要使用之前实现的队列
BinaryTreeComplete:
🔑 核心思想 🔑
想必完全二叉树在此处出现一定跟层序有关系
层序遍厉,把空也入队列
完全二叉树,非空是连续的,空也是连续的
非完全二叉树,非空就不是连续的,空也是不连续的
❗ 这里需要三个文件 ❕
1️⃣ Queue_LeveOrder.h,用于函数的声明
#pragma once //头 #include<stdio.h> #include<assert.h> #include<stdbool.h> #include<stdlib.h> //结构体 typedef struct BinaryTreeNode* QDataType; typedef struct QueueNode { struct QueueNode* next; //指向下一个节点 QDataType data; //存储整型数据 }QueueNode; typedef struct Queue { QueueNode* phead;//头指针 QueueNode* ptail;//尾指针 }Queue; //函数 void QueueInit(Queue* pq); void QueuePush(Queue* pq, QDataType x); bool QueueEmpty(Queue* pq); void QueuePop(Queue* pq); QDataType QueueSize(Queue* pq); QDataType QueueFront(Queue* pq); QDataType QueueBack(Queue* pq); void QueueDestory(Queue* pq);
2️⃣ Queue_LeveOrder.c,用于函数的实现
#include"Queue_LeveOrder.h" void QueueInit(Queue* pq) { assert(pq); //把2个指针置空 pq->phead = pq->ptail = NULL; } void QueuePush(Queue* pq, QDataType x) { assert(pq); //malloc空间,如果需要频繁的开辟空间建议再实现一个BuyQueueNode用于malloc QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode)); if (newnode == NULL) { printf("malloc fail\n"); exit(-1); } newnode->data = x; newnode->next = NULL; //第一次插入 if (pq->phead == NULL) { pq->phead = pq->ptail = newnode; } //非第一次插入 else { pq->ptail->next = newnode; pq->ptail = newnode; } } bool QueueEmpty(Queue* pq) { assert(pq); //空链表返回true,非空链表返回false return pq->phead == NULL; } void QueuePop(Queue* pq) { assert(pq); //链表为空时不能删除 assert(!QueueEmpty(pq)); //只有一个节点的情况 if (pq->phead->next == NULL) { free(pq->phead); pq->phead = pq->ptail = NULL; } //多个节点的情况 else { QueueNode* next = pq->phead->next; free(pq->phead) ; pq->phead = next; } } QDataType QueueSize(Queue* pq) { assert(pq); //如果需要频繁的调用QueueSize这个接口,可以在Queue这个结构体中增加一个成员用于记录长度 int sz = 0; QueueNode* cur = pq->phead; while (cur) { sz++; cur = cur->next; } return sz; } QDataType QueueFront(Queue* pq) { assert(pq); //链表为空时不能取头 assert(!QueueEmpty(pq)); return pq->phead->data; } QDataType QueueBack(Queue* pq) { assert(pq); //链表为空时不能取尾 assert(!QueueEmpty(pq)); return pq->ptail->data; } void QueueDestory(Queue* pq) { assert(pq); QueueNode* cur = pq->phead; //遍历链表 while (cur) { QueueNode* next = cur->next; free(cur); cur = next; } pq->phead = pq->ptail = NULL; }
3️⃣ Test.c,用于函数的测试
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> typedef int BTDataType; typedef struct BinaryTreeNode { BTDataType _data; struct BinaryTreeNode* _left; struct BinaryTreeNode* _right; }BTNode; //从此处包含Queue.h文件 #include"Queue_LeveOrder.h" BTNode* BuyNode(BTDataType x) { BTNode* node = malloc(sizeof(BTNode)); node->_data = x; node->_left = NULL; node->_right = NULL; return node; } //创建二叉树 BTNode* BinaryCreatBinaryTree() { BTNode* node1 = BuyNode(1); BTNode* node2 = BuyNode(2); BTNode* node3 = BuyNode(3); BTNode* node4 = BuyNode(4); BTNode* node5 = BuyNode(5); BTNode* node6 = BuyNode(6); node1->_left = node2; node1->_right = node3; node2->_left = node4; node3->_left = node5; node3->_right = node6; return node1; } //层序遍厉 void BinaryTreeLeveOrder(BTNode* root) { Queue q; QueueInit(&q); if (root) { //入队列 QueuePush(&q, root); } while (!QueueEmpty(&q)) { //取队头的数据 BTNode* front = QueueFront(&q); //出队 QueuePop(&q); printf("%d ", front->_data); if (front->_left) { //入左子树 QueuePush(&q, front->_left); } if (front->_right) { //入右子树 QueuePush(&q, front->_right); } } printf("\n"); QueueDestory(&q); } //判断二叉树是否是完全二叉树 bool BinaryTreeComplete(BTNode* root) { Queue q; QueueInit(&q); if (root) { //入队列 QueuePush(&q, root); } while (!QueueEmpty(&q)) { //取队头的数据 BTNode* front = QueueFront(&q); //出队 QueuePop(&q); //遇到空就break出去再判断 if(front == NULL) { break; } //入左子树 QueuePush(&q, front->_left); //入右子树 QueuePush(&q, front->_right); } //队列中全是空,就是完全二叉树;还有非空,就不是完全二叉树 while(!QueueEmpty(&q)) { BTNode* front = QueueFront(&q); QueuePop(&q); //非空 if(front) { QueueDestory(&q); return false; } } //全是空 QueueDestory(&q); return true; } //后序销毁二叉树 void BinaryTreeDestroy(BTNode* root) { if (root == NULL) return; BinaryTreeDestroy(root->_left); BinaryTreeDestroy(root->_right); free(root); } int main() { BTNode* root = BinaryCreatBinaryTree(); BinaryTreeLeveOrder(root); printf("BinaryTreeComplete:%d\n", BinaryTreeComplete(root)); BinaryTreeDestroy(root); root = NULL; return 0; }