仅不到五万字轻松了解二叉树和堆 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;
}
相关文章
|
19天前
【每日一题Day361】LC2558从数量最多的堆取走礼物 | 大顶堆
【每日一题Day361】LC2558从数量最多的堆取走礼物 | 大顶堆
27 0
|
19天前
|
存储 算法
算法编程(九):最小栈
算法编程(九):最小栈
26 0
|
19天前
|
算法
实现链表的运势推算
【5月更文挑战第4天】这段代码定义了一个用于占卜运算的结构,包含卦象数据、格式化输出和计算参数。提供了构造函数`MakeNewDataTao`来初始化结构体。代码的目标是实现占卜运势的计算流程。
16 0
|
8月前
|
算法
【算法挨揍日记】day06——1004. 最大连续1的个数 III、1658. 将 x 减到 0 的最小操作数
1004. 最大连续1的个数 III 题目描述: 给定一个二进制数组 nums 和一个整数 k,如果可以翻转最多 k 个 0 ,则返回 数组中连续 1 的最大个数 。
374 1
|
10月前
|
存储 C语言
IT公司的吉祥“树” 二叉树-(堆)C语言创建(一)
IT公司的吉祥“树” 二叉树-(堆)C语言创建
75 0
|
10月前
|
存储 算法 C语言
IT公司的吉祥“树” 二叉树-(堆)C语言创建(二)
IT公司的吉祥“树” 二叉树-(堆)C语言创建
57 0
|
11月前
【开卷数据结构 】哈夫曼编码
【开卷数据结构 】哈夫曼编码
117 1
|
12月前
[leetcode] 1675. 数组的最小偏移量 | 思维贪心 | 大疆笔试题
[leetcode] 1675. 数组的最小偏移量 | 思维贪心 | 大疆笔试题
83 0
|
存储 算法 C++
一篇文章带你彻底理解线性表,超详细千字总结对比!
线性表 本章将详细地介绍线性表,包含线性存储和链式存储,同时介绍了抽象数据类型(ADT),并且使用cpp代码结合理论进行讲解,最后也附上了一些线性表相关的经典题型以便读者能理解线性表的作用以及能运用线性表。 可以转载,但请声明源链接:文章源链接justin3go.com(有些latex公式某些平台不能渲染可查看这个网站)
73 0
|
存储 算法 索引
【每日挠头算法题】LeetCode 1337. 矩阵中战斗力最弱的 K 行 —— 二分 + 排序 / 堆
【每日挠头算法题】LeetCode 1337. 矩阵中战斗力最弱的 K 行 —— 二分 + 排序 / 堆
103 0
【每日挠头算法题】LeetCode 1337. 矩阵中战斗力最弱的 K 行 —— 二分 + 排序 / 堆