【C语言 - 数据结构】树、二叉树(下篇)(下)

简介: 【C语言 - 数据结构】树、二叉树(下篇)

3.3怎么求第k层节点的个数?


核心思路:递归返回第k-1层左右结点相加的值

1669440614564.jpg

int BTreekLeafSize(BTNode* root, int k)
{
       assert(k >= 1);
       if (root == NULL) return 0;
       if (k == 1) return 1;
       return BTreekLeafSize(root->left, k - 1) + BTreekLeafSize(root->right, k - 1);//返回左结点和右结点的上一层
}

3.4求一棵树的高度


思想:比较左右子树的高度,并且返回高度大的加一(原因:加根结点)

int BTreeDepth(BTNode* root)
{
       if (root == NULL)
              return 0;
       int leftDepth = BTreeDepth(root->left);
       int rightDepth = BTreeDepth(root->right);
       return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}


3.5二叉树查找值为x的结点


1669440667333.jpg

思路:用前序遍历去递归搜索,先搜左子树,如果左子树没有,就返回一个NULL到根结点,然后根结点再递归搜索右树,如果右树有就返回那个点的值。

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)//如果左边返回的不是NULL
       {
              return ret1;
       }
       BTNode* ret2 = BTreeFind(root->right, x);
       if (ret2)
       {
              return ret2;
       }
       return NULL;
}


3.6判断一棵树是不是完全二叉树


思路:就是把空也当作二叉树的节点放进去,然后运用层序遍历,


如果在遍历的中间过程中遇到空就说明不是完全二叉树。


队列不能直接像数组一样遍历


1669440692995.jpg


//判断一棵树是不是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
       Queue q;
       QueueInit(&q);
       if (root)
       {
              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)//如果出到非空,那么就不是完全二叉树
              {
                      return false;
              }
       }
       return true;
}


四、二叉树oj题


1、965. 单值二叉树 - 力扣(LeetCode)


1669440742029.jpg

bool isUnivalTree(struct TreeNode* root)
{
    if(root == NULL) return true;
    if(root->left && root->left->val != root->val)//如果左结点不为空,且左树结点的值不等于根的值,返回false
         return false;
    if(root->right && root->right->val != root->val)//如果右结点不为空,且右树结点的值不等于根的值,返回false
        return false;
    return isUnivalTree(root->left) && isUnivalTree(root->right);//递归判断
}

2、100. 相同的树 - 力扣(LeetCode)


1669440767996.jpg


思路:先判断两棵树是不是都是空树,再判断如果一个为空一个不为空,最后递归

bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    //判断两个树的根是不是都为空
    if(p == NULL && q == NULL)
        return true;
    //判断两个树的其中一颗树的结点为空时,另一个不为空
    if(p == NULL || q == NULL)
        return false;
    //判断两个树的根节点是否是同值
    if(p->val != q->val)
        return false;
        //递归判断
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

注意:这里的判断不能写成p->left->val != q->left->val

会报错


3、101. 对称二叉树 - 力扣(LeetCode)


1669440796631.jpg


思路:写一个辅助函数,舍弃根结点,判断左边这个树是否与右边这个树对称

bool isSymmetricTree(struct TreeNode* p, struct TreeNode* q)
{
    //如果root的左和右节点都为空
    if(p == NULL && q == NULL) 
    return true;
    //如果一个为空一个不为空
    if(p == NULL || q == NULL) 
    return false;
    return p->val == q->val 
    && isSymmetricTree(p->left, q->right)
    && isSymmetricTree(p->right, q->left);
}
bool isSymmetric(struct TreeNode* root)
{
    if(root == NULL) 
    return true;
    return isSymmetricTree(root->left, root->right);
}


4、144. 二叉树的前序遍历 - 力扣(LeetCode)


1669440823695.jpg


题目意思解释:Note: The returned array must be malloced, assume caller calls free().


这句话的意思是数组要malloc, 然后caller系统会帮你free掉


int* returnSize的意思是返回结点的个数


代码如下所示:

int TreeSize(struct TreeNode* root)//计算树的结点个数,方便malloc空间
{
    return root == NULL ? 0 : TreeSize(root->left) + 
    TreeSize(root->right) + 1;
}
//定义一个子函数去完成前序遍历
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)//int*returnSize是输出型参数
{
    int size = TreeSize(root);
    //不考虑动态扩容
    int* a = malloc(sizeof(int)*size);
    int i = 0;
    *returnSize = size;
    _preorder(root, a, &i);
    return a;
}

因为之后的二叉树中序以及后序遍历思路差不多,所以如果读者有兴趣可以根据这个思路去做。


5、572. 另一棵树的子树 - 力扣(LeetCode)


1669440849422.jpg


思路:左边树中每一个子树都比较isSameTree


遍历左边的每个节点,做子树的根,跟右边的子树都比较一下isSameTree


bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    //两棵树的根都为空
    if (p == NULL && q == NULL)
        return true;
    //只有一颗树为空 此时已经有同位置的节点不相等
    if(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;
    if(isSameTree(root, subRoot))
    {
        return true;
    }
    return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}


6.二叉树遍历_牛客题霸_牛客网 (nowcoder.com)


先序遍历字符串构造的二叉树(前序)


递归、分治的思想

1669440882489.jpg

1669440896236.jpg

#include<stdio.h>
#include<string.h>
//构造结构体
typedef struct BinaryTreeNode
{
    char data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
}BTNode;
//造树
BTNode* CreatTree(char* a, int* pi)
{
    if(a[*pi] == '#')
    {
        (*pi)++;
        return NULL;
    }
    BTNode* root = (BTNode*)malloc(sizeof(BTNode));
    root->data = a[(*pi)++];
    root->left = CreatTree(a, pi);
    root->right = CreatTree(a, pi);
    return root;
}
void InOrder(BTNode* root)
{
    if(root == NULL)//这里root直接等于NULL判断便可,不需要‘#
    {
        return;
    }
    InOrder(root->left);
    printf("%c ", root->data);
    InOrder(root->right);
}
//main函数部分
int main ()
{
    char a[101];
    scanf("%s", a);
    int i = 0;
    BTNode* tree = CreatTree(a, &i);
    InOrder(tree);
    return 0;
}
相关文章
|
3天前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
45 9
|
2天前
|
存储 搜索推荐 算法
【数据结构】树型结构详解 + 堆的实现(c语言)(附源码)
本文介绍了树和二叉树的基本概念及结构,重点讲解了堆这一重要的数据结构。堆是一种特殊的完全二叉树,常用于实现优先队列和高效的排序算法(如堆排序)。文章详细描述了堆的性质、存储方式及其实现方法,包括插入、删除和取堆顶数据等操作的具体实现。通过这些内容,读者可以全面了解堆的原理和应用。
32 16
|
2天前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
28 8
|
4天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
26 4
|
4天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
18 0
|
存储 缓存 C语言
数据结构——双链表(C语言)
数据结构——双链表(C语言)
|
5月前
|
存储
数据结构——双向链表(C语言版)
数据结构——双向链表(C语言版)
30 2
|
5月前
|
算法 C语言
数据结构——单向链表(C语言版)
数据结构——单向链表(C语言版)
45 2
|
测试技术 C语言
数据结构单链表的实现(C语言)
数据结构单链表的实现(C语言)
26 0
|
6月前
|
存储 缓存 程序员
初阶数据结构之---顺序表和链表(C语言)
初阶数据结构之---顺序表和链表(C语言)