二叉树(下)+Leetcode每日一题——“数据结构与算法”“对称二叉树”“另一棵树的子树”“二叉树的前中后序遍历”

简介: 二叉树(下)+Leetcode每日一题——“数据结构与算法”“对称二叉树”“另一棵树的子树”“二叉树的前中后序遍历”

这个题目需要重新定义一个函数,函数参数需要有左子树和右子树,题目所给定的函数无法解决问题。

bool _isSymmetric(struct TreeNode* leftRoot,struct TreeNode* rightRoot)
{
    //左子树和右子树同时为空
    if(leftRoot==NULL&&rightRoot==NULL)
    {
        return true;
    }
    //一棵树为空,另一棵树不为空
    if((leftRoot==NULL&&rightRoot!=NULL)||
    (leftRoot!=NULL&&rightRoot==NULL))
    {
        return false;
    }
    //左子树的根和右子树的根不相等
    //这就必然不对称
    if(leftRoot->val!=rightRoot->val)
    {
        return false;
    }
    return _isSymmetric(leftRoot->left,rightRoot->right)&&
            _isSymmetric(leftRoot->right,rightRoot->left);
}
bool isSymmetric(struct TreeNode* root){
    return _isSymmetric(root->left,root->right);
}


每个不为空的结点,都可以认为是一棵子树的根

//两棵树相同
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    //两个都为空
    if(p==NULL&&q==NULL)
    {
        return true;
    }
    //一个为空,另一个不为空
    if((p==NULL&&q!=NULL)||(p!=NULL&&q==NULL))
    {
        return false;
    }
    //根不相等
    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){
    if(root==NULL)
    {
        return false;
    }
    //root和subRoot相同
    if(isSameTree(root,subRoot))
    {
        return true;
    }
    //root的左子树与subRoot有相同或者root的右子树与subRoot有相同
    //满足其中一个条件即可,所以用||
    return isSubtree(root->left,subRoot)||
            isSubtree(root->right,subRoot);
}


递归里面传数组下标要注意!!!

每个栈帧里面都有一个数组下标!!!

所以要传数组下标的地址。

int TreeSize(struct TreeNode* root)
{
    return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;
}
//递归里面传数组下标要注意!!!
//每个栈帧里面都有一个i
void preorder(struct TreeNode* root,int* a,int* pi)
{
    if(root==NULL)
    {
        return;
    }
    a[(*pi)++]=root->val;
    preorder(root->left,a,pi);
    preorder(root->right,a,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize){
    //root是输入型参数,returnSize是返回型参数
    *returnSize=TreeSize(root);
    int* a=(int*)malloc(*returnSize*sizeof(int));
    int i=0;
    preorder(root,a,&i);
    return a;
}

当然,这个题目还有另外一种解法,就是把i作为全局变量,但是这样要特别注意,稍有不慎就会出错

int TreeSize(struct TreeNode* root)

{

   return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;

}

//递归里面传数组下标要注意!!!

//每个栈帧里面都有一个i

int i=0;

void preorder(struct TreeNode* root,int* a)

{

   if(root==NULL)

   {

       return;

   }

   a[i++]=root->val;

   preorder(root->left,a);

   preorder(root->right,a);

}

int* preorderTraversal(struct TreeNode* root, int* returnSize){

   //root是输入型参数,returnSize是返回型参数

   *returnSize=TreeSize(root);

   int* a=(int*)malloc(*returnSize*sizeof(int));

   i=0;

   preorder(root,a);

   return a;

}

int TreeSize(struct TreeNode* root)

{

   return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;

}

void inorder(struct TreeNode* root,int* a,int* pi)

{

   if(root==NULL)

   {

       return;

   }

   inorder(root->left,a,pi);

   a[(*pi)++]=root->val;

   inorder(root->right,a,pi);

}

int* inorderTraversal(struct TreeNode* root, int* returnSize){

   //root是输入型参数,returnSize是返回型参数

   *returnSize=TreeSize(root);

   int* a=(int*)malloc(*returnSize*sizeof(int));

   int i=0;

   inorder(root,a,&i);

   return a;

}

int TreeSize(struct TreeNode* root)

{

   return root==NULL?0:TreeSize(root->left)+TreeSize(root->right)+1;

}

void postorder(struct TreeNode* root,int* a,int* pi)

{

   if(root==NULL)

   {

       return;

   }

   postorder(root->left,a,pi);

   postorder(root->right,a,pi);

    a[(*pi)++]=root->val;

}

int* postorderTraversal(struct TreeNode* root, int* returnSize){

   //root是输入型参数,returnSize是返回型参数

   *returnSize=TreeSize(root);

   int* a=(int*)malloc(*returnSize*sizeof(int));

   int i=0;

   postorder(root,a,&i);

   return a;

}


层序遍历

除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层 上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

1出来带2和4,2出来带3和NULL,4出来带和6

写这个代码的核心是得有一个队列!!!

Queue.h的内容:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef struct BinaryTreeNode* QDataType;
// 链式结构:表示队列 
typedef struct QueueNode
{
  struct QueueNode* next;
  QDataType data;
}QueueNode;
// 队列的结构 
typedef struct Queue
{
  QueueNode* phead;//头指针
  QueueNode* ptail;//尾指针
  int size;
}Queue;
// 初始化队列
void QueueInit(Queue* pq);
 
// 销毁队列 
void QueueDestroy(Queue* pq);
 
// 队尾入队列 
void QueuePush(Queue* pq, QDataType x);
 
// 队头出队列 
void QueuePop(Queue* pq);
 
// 获取队列头部元素 
QDataType QueueFront(Queue* pq);
 
// 获取队列队尾元素 
QDataType QueueBack(Queue* pq);
 
// 获取队列中有效元素个数 
int QueueSize(Queue* pq);
 
// 检测队列是否为空
bool QueueEmpty(Queue* pq);

Queue.c的内容:

#include"Queue.h"
// 初始化队列
void QueueInit(Queue* pq)
{
  assert(pq);
  pq->phead = NULL;
  pq->ptail = NULL;
  pq->size = 0;
}
// 销毁队列 
void QueueDestroy(Queue* pq)
{
  assert(pq);
  QueueNode* cur = pq->phead;
  while (cur != NULL)
  {
    QueueNode* next = cur->next;
    free(cur);
    cur = next;
  }
  pq->phead = pq->ptail = NULL;
  pq->size = 0;
}
// 队尾入队列 
void QueuePush(Queue* pq, QDataType x)
{
  assert(pq);
  QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
  if (newnode == NULL)
  {
    perror("malloc fail");
    return;
  }
  newnode->data = x;
  newnode->next = NULL;
  //是空队列的情况
  if (pq->ptail == NULL)
  {
    assert(pq->phead == NULL);
    pq->phead = pq->ptail = newnode;
  }
  else
  {
    pq->ptail->next = newnode;
    pq->ptail = newnode;
  }
  pq->size++;
}
// 检测队列是否为空
bool QueueEmpty(Queue* pq)
{
  assert(pq);
  return pq->phead == NULL && pq->ptail == NULL;
}
// 队头出队列 
void QueuePop(Queue* pq)
{
  assert(pq);
  assert(!QueueEmpty(pq));
  //1.一个结点
  //2.多个结点
  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;
  }
  pq->size--;
}
// 获取队列头部元素 
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;
}
 
// 获取队列中有效元素个数 
int QueueSize(Queue* pq)
{
  assert(pq);
  return pq->size;
}

层序遍历源代码:

//层序遍历
void LevelOrder(BTNode* root)
{
  Queue q;
  QueueInit(&q);
  if (root != NULL)
  {
    QueuePush(&q, root);
  }
  while (!QueueEmpty(&q))
  {
    BTNode* front = QueueFront(&q);
    QueuePop(&q);
    printf("%d ", front->data);
    if (front->left != NULL)
    {
      QueuePush(&q, front->left);
    }
    if (front->right != NULL)
    {
      QueuePush(&q, front->right);
    }
  }
  printf("\n");
  QueueDestroy(&q);
}


二叉树销毁

//二叉树销毁
void BTreeDestroy(BTNode* root)
{
  if (root == NULL)
  {
    return;
  }
  BTreeDestroy(root->left);
  BTreeDestroy(root->right);
  free(root);
}

通 过 前 序 遍 历 的 数 组 " A B D # # E # H # # C F # # G # # " 构 建 二 叉 树

根        左子树        右子树

#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 = (BTNode*)malloc(sizeof(BTNode));
  if (node == NULL)
  {
    perror("malloc fail");
    return NULL;
  }
  node->data = x;
  node->left = NULL;
  node->right = NULL;
  return node;
}
BTNode* CreatTree(char* a,int* pi)
{
    if(a[*pi]=='#')
    {
        (*pi)++;
        return NULL;
    }
    BTNode* root=BuyNode(a[*pi]);
    (*pi)++;
    root->left=CreatTree(a,pi);
    root->right=CreatTree(a,pi);
    return root;
}
//中序
void InOrder(BTNode* root)
{
  if (root == NULL)
  {
    return;
  }
  InOrder(root->left);
  printf("%c ", root->data);
  InOrder(root->right);
}
int main()
{
    char a[100];
    scanf("%s",a);
    int i=0;
    BTNode*root=CreatTree(a,&i);
    InOrder(root);
    printf("\n");
    return 0;
 
}

判断二叉树是否是完全二叉树

完全二叉树的特征是:层序遍历去走,它是连续的!!!

1出来带2和4,2出来带3和NULL,4出来带5和6,3出来带NULL和NULL,但是,3后面的NULL的后面竟然还有非空,这就证明此树是一棵非完全二叉树。

1出来带2和4,2出来带3和7,4出来带5和6,3出来带8和NULL,7出来带NULL和NULL,5出来带NULL和NULL,6出来带NULL和NULL,8出来带NULL和NULL,也就是说,队列里面的全都是空了,这一定是一棵完全二叉树。

//判断二叉树是否是完全二叉树
bool BTreeComplete(BTNode* root)
{
  Queue q;
  QueueInit(&q);
  if (root != NULL)
  {
    QueuePush(&q, root);
  }
  while (!QueueEmpty(&q))
  {
    BTNode* front = QueueFront(&q);
    QueuePop(&q);
    //遇到空就跳出循环
    if (front == NULL)
    {
      break;
    }
    QueuePush(&q, front->left);
    QueuePush(&q, front->right);
  }
  //检查后面的结点有没有非空
  //有非空,就不是完全二叉树
  while (!QueueEmpty(&q))
  {
    BTNode* front = QueueFront(&q);
    QueuePop(&q);
    if (front != NULL)
    {
      QueueDestroy(&q);
      return false;
    }
  }
  QueueDestroy(&q);
  return true;
}

1.某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为( A )

A ABDHECFG

B ABCDEFGH

C HDBEAFCG

D HDEBFGCA

2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为( A )

A E

B F

C G

D H

此题与中序遍历无关(中序遍历是迷惑人的),光看先序遍历就可以看出来,先序遍历就是根        左子树        右子树,所以E就是根结点。

但如果是想还原出这棵二叉树,中序遍历就很重要啦!!!

3.设一棵二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为( D )。

A adbce

B decab

C debac

D abcde

后序遍历序列最后一个是a,所以a就是根节点!!!

4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为( A )

A FEDCBA

B CBAFED

C DEFCBA

D ABCDEF

二叉树的性质


整个二叉树的源代码:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"Queue.h"
typedef int BTDataType;
typedef struct BinaryTreeNode
{
   BTDataType data;
   struct BinaryTreeNode* left;
   struct BinaryTreeNode* right;
}BTNode;

BTNode* BuyNode(BTDataType x)
{
   BTNode* node = (BTNode*)malloc(sizeof(BTNode));
   if (node == NULL)
   {
       perror("malloc fail");
       return NULL;
   }
   node->data = x;
   node->left = NULL;
   node->right = NULL;
   return node;
}

BTNode* CreatBinaryTree()
{
   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 = node4;
   node2->left = node3;
   node4->left = node5;
   node4->right = node6;
   return node1;
}

//前序
void PrevOrder(BTNode* root)
{
   if (root == NULL)
   {
       printf("NULL ");
       return;
   }
   printf("%d ", root->data);
   PrevOrder(root->left);
   PrevOrder(root->right);
}

//中序
void InOrder(BTNode* root)
{
   if (root == NULL)
   {
       printf("NULL ");
       return;
   }
   InOrder(root->left);
   printf("%d ", root->data);
   InOrder(root->right);
}

//后序
void PostOrder(BTNode* root)
{
   if (root == NULL)
   {
       printf("NULL ");
       return;
   }
   PostOrder(root->left);
   PostOrder(root->right);
   printf("%d ", root->data);
}

 

二叉树结点个数
//int size = 0;//全局变量
//int BTreeSize(BTNode* root)
//{
//    if (root == NULL)
//    {
//        return;
//    }
//    else
//    {
//        ++size;
//    }
//    BTreeSize(root->left);
//    BTreeSize(root->right);
//}
二叉树结点个数
//int BTreeSize(BTNode* root)
//{
//    if (root == NULL)
//    {
//        return 0;
//    }
//    else
//    {
//        return BTreeSize(root->left) + BTreeSize(root->right) + 1;
//    }
//}

//二叉树结点个数
int BTreeSize(BTNode* root)
{
   return root == NULL ? 0 : BTreeSize(root->left) + BTreeSize(root->right) + 1;
}

//求叶子结点的个数
int BTreeleafSize(BTNode* root)
{
   if (root == NULL)
   {
       return 0;
   }
   if (root->left == NULL && root->right == NULL)
   {
       return 1;
   }
   return BTreeleafSize(root->left) + BTreeleafSize(root->right);
}

//求二叉树的高度
int BTreeHeight(BTNode* root)
{
   if (root == NULL)
   {
       return 0;
   }
   else
   {
       int leftHeight = BTreeHeight(root->left);
       int rightHeight = BTreeHeight(root->right);
       return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
   }
}

// 二叉树第k层节点个数
int BTreeLevelKSize(BTNode* root, int k)
{
   assert(k > 0);
   if (root == NULL)//无论k是多少
   {
       return 0;
   }
   //root一定不为空
   if (k == 1)
   {
       return 1;
   }
   //root不为空并且k不为1
   return BTreeLevelKSize(root->left, k - 1) + BTreeLevelKSize(root->right, k - 1);
}

// 二叉树查找值为x的节点
BTNode* BTreeFind(BTNode* root, BTDataType x)
{
   if (root == NULL)
   {
       return NULL;
   }
   if (root->data == x)
   {
       return root;
   }
   BTNode* ret1 = BTreeFind(root->left, x);
   if (ret1)
   {
       return ret1;
   }
   BTNode* ret2 = BTreeFind(root->right, x);
   if (ret2)
   {
       return ret2;
   }
   return NULL;
}

//层序遍历
void LevelOrder(BTNode* root)
{
   Queue q;
   QueueInit(&q);
   if (root != NULL)
   {
       QueuePush(&q, root);
   }
   while (!QueueEmpty(&q))
   {
       BTNode* front = QueueFront(&q);
       QueuePop(&q);
       printf("%d ", front->data);
       if (front->left != NULL)
       {
           QueuePush(&q, front->left);
       }
       if (front->right != NULL)
       {
           QueuePush(&q, front->right);
       }
   }
   printf("\n");
   QueueDestroy(&q);
}

//二叉树销毁
void BTreeDestroy(BTNode* root)
{
   if (root == NULL)
   {
       return;
   }
   BTreeDestroy(root->left);
   BTreeDestroy(root->right);
   free(root);
}

//判断二叉树是否是完全二叉树
bool BTreeComplete(BTNode* root)
{
   Queue q;
   QueueInit(&q);
   if (root != NULL)
   {
       QueuePush(&q, root);
   }
   while (!QueueEmpty(&q))
   {
       BTNode* front = QueueFront(&q);
       QueuePop(&q);
       //遇到空就跳出循环
       if (front == NULL)
       {
           break;
       }
       QueuePush(&q, front->left);
       QueuePush(&q, front->right);
   }
   //检查后面的结点有没有非空
   //有非空,就不是完全二叉树
   while (!QueueEmpty(&q))
   {
       BTNode* front = QueueFront(&q);
       QueuePop(&q);
       if (front != NULL)
       {
           QueueDestroy(&q);
           return false;
       }
   }
   QueueDestroy(&q);
   return true;
}

int main()
{
   BTNode* root = CreatBinaryTree();
   PrevOrder(root);
   printf("\n");

   InOrder(root);
   printf("\n");

   PostOrder(root);
   printf("\n");

   /*BTreeSize(root);
   printf("BTreeSize:%d\n", size);

   size = 0;
   BTreeSize(root);
   printf("BTreeSize:%d\n", size);

   size = 0;
   BTreeSize(root);
   printf("BTreeSize:%d\n", size);*/

   printf("BTreeSize:%d\n",BTreeSize(root));

   printf("BTreeleafSize:%d\n", BTreeleafSize(root));

   printf("BTreeHeight:%d\n", BTreeHeight(root));

   printf("BTreeLevelKSize:%d\n", BTreeLevelKSize(root, 3));

   printf("BTreeFind:%p\n", BTreeFind(root, 3));

   LevelOrder(root);

   BTreeDestroy(root);
   root = NULL;

   return 0;
}

 

好啦,小雅兰的今日分享就到这里啦,还要继续加油学习噢!!!


相关文章
|
1月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
49 1
|
8天前
|
C语言
数据结构基础详解(C语言):图的基本概念_无向图_有向图_子图_生成树_生成森林_完全图
本文介绍了图的基本概念,包括图的定义、无向图与有向图、简单图与多重图等,并解释了顶点度、路径、连通性等相关术语。此外还讨论了子图、生成树、带权图及几种特殊形态的图,如完全图和树等。通过这些概念,读者可以更好地理解图论的基础知识。
|
10天前
|
存储 算法 C语言
数据结构基础详解(C语言): 二叉树的遍历_线索二叉树_树的存储结构_树与森林详解
本文从二叉树遍历入手,详细介绍了先序、中序和后序遍历方法,并探讨了如何构建二叉树及线索二叉树的概念。接着,文章讲解了树和森林的存储结构,特别是如何将树与森林转换为二叉树形式,以便利用二叉树的遍历方法。最后,讨论了树和森林的遍历算法,包括先根、后根和层次遍历。通过这些内容,读者可以全面了解二叉树及其相关概念。
|
29天前
|
算法
测试工程师的技能升级:LeetCode算法挑战与职业成长
这篇文章通过作者亲身体验LeetCode算法题的过程,探讨了测试工程师学习算法的重要性,并强调了算法技能对于测试职业成长的必要性。
42 1
测试工程师的技能升级:LeetCode算法挑战与职业成长
|
10天前
|
存储 机器学习/深度学习 C语言
数据结构基础详解(C语言): 树与二叉树的基本类型与存储结构详解
本文介绍了树和二叉树的基本概念及性质。树是由节点组成的层次结构,其中节点的度为其分支数量,树的度为树中最大节点度数。二叉树是一种特殊的树,其节点最多有两个子节点,具有多种性质,如叶子节点数与度为2的节点数之间的关系。此外,还介绍了二叉树的不同形态,包括满二叉树、完全二叉树、二叉排序树和平衡二叉树,并探讨了二叉树的顺序存储和链式存储结构。
|
10天前
|
存储 C语言
数据结构基础详解(C语言): 树与二叉树的应用_哈夫曼树与哈夫曼曼编码_并查集_二叉排序树_平衡二叉树
本文详细介绍了树与二叉树的应用,涵盖哈夫曼树与哈夫曼编码、并查集以及二叉排序树等内容。首先讲解了哈夫曼树的构造方法及其在数据压缩中的应用;接着介绍了并查集的基本概念、存储结构及优化方法;随后探讨了二叉排序树的定义、查找、插入和删除操作;最后阐述了平衡二叉树的概念及其在保证树平衡状态下的插入和删除操作。通过本文,读者可以全面了解树与二叉树在实际问题中的应用技巧和优化策略。
|
1月前
|
存储 算法 Linux
【数据结构】树、二叉树与堆(长期维护)(1)
【数据结构】树、二叉树与堆(长期维护)(1)
|
1月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
36 6
|
1月前
|
算法
【数据结构】树、二叉树与堆(长期维护)(2)
【数据结构】树、二叉树与堆(长期维护)(2)
【数据结构】树、二叉树与堆(长期维护)(2)
|
1月前
|
存储 算法 Java
LeetCode经典算法题:打家劫舍java详解
LeetCode经典算法题:打家劫舍java详解
46 2