仅不到五万字轻松了解二叉树和堆 4

简介: 仅不到五万字轻松了解二叉树和堆
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 类型大小的数组。再调用子函数进行前序递归:如果每层函数栈帧中节点为空则结束栈帧,否则把节点放到数组里,并继续递归

leetcode原题

#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

🔑 核心思想:类似前序

leetcode原题

#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

🔑 核心思想:类似前序

leetcode原题

#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;否则继续递归

leetcode原题

#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 类型的题需要我们自己创建树 ❕

根据题意中先序遍历的字符串可以得到:

先前序构建树,再中序输出树

nowcode原题

#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;
}
相关文章
|
6月前
【每日一题Day361】LC2558从数量最多的堆取走礼物 | 大顶堆
【每日一题Day361】LC2558从数量最多的堆取走礼物 | 大顶堆
38 0
|
3月前
【刷题记录】尼科彻斯定理、数对、环形结构
【刷题记录】尼科彻斯定理、数对、环形结构
|
6月前
|
算法
实现链表的运势推算
【5月更文挑战第4天】这段代码定义了一个用于占卜运算的结构,包含卦象数据、格式化输出和计算参数。提供了构造函数`MakeNewDataTao`来初始化结构体。代码的目标是实现占卜运势的计算流程。
28 0
|
算法
【算法挨揍日记】day06——1004. 最大连续1的个数 III、1658. 将 x 减到 0 的最小操作数
1004. 最大连续1的个数 III 题目描述: 给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。
407 1
|
存储 C语言
IT公司的吉祥“树” 二叉树-(堆)C语言创建(一)
IT公司的吉祥“树” 二叉树-(堆)C语言创建
97 0
|
存储 算法 C语言
IT公司的吉祥“树” 二叉树-(堆)C语言创建(二)
IT公司的吉祥“树” 二叉树-(堆)C语言创建
76 0
|
存储 算法 索引
【每日挠头算法题】LeetCode 1337. 矩阵中战斗力最弱的 K 行 —— 二分 + 排序 / 堆
【每日挠头算法题】LeetCode 1337. 矩阵中战斗力最弱的 K 行 —— 二分 + 排序 / 堆
119 0
【每日挠头算法题】LeetCode 1337. 矩阵中战斗力最弱的 K 行 —— 二分 + 排序 / 堆
【八月】 每日一题 - 768. 最多能完成排序的块 I and II
【八月】 每日一题 - 768. 最多能完成排序的块 I and II
92 0
【八月】 每日一题 - 768. 最多能完成排序的块 I and II
|
存储 算法 容器
一次字节面试,被二叉树的层序遍历捏爆了
大家好,我是bigsai,在数据结构与算法中,二叉树无论是考研、笔试都是非常高频的考点内容,在二叉树中,二叉树的遍历又是非常重要的知识点,今天给大家讲讲二叉树的层序遍历。
107 0
一次字节面试,被二叉树的层序遍历捏爆了
|
人工智能 C++
牛客练习赛14 B.区间的连续段(前缀和 倍增)
牛客练习赛14 B.区间的连续段(前缀和 倍增)
90 0