【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;
}
相关文章
|
2月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
68 1
|
12天前
|
存储 C++
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
【数据结构——树】哈夫曼树(头歌实践教学平台习题)【合集】目录 任务描述 相关知识 测试说明 我的通关代码: 测试结果:任务描述 本关任务:编写一个程序构建哈夫曼树和生成哈夫曼编码。 相关知识 为了完成本关任务,你需要掌握: 1.如何构建哈夫曼树, 2.如何生成哈夫曼编码。 测试说明 平台会对你编写的代码进行测试: 测试输入: 1192677541518462450242195190181174157138124123 (用户分别输入所列单词的频度) 预
49 14
【C++数据结构——树】哈夫曼树(头歌实践教学平台习题) 【合集】
|
12天前
|
Java C++
【C++数据结构——树】二叉树的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现二叉树的基本运算。​ 相关知识 创建二叉树 销毁二叉树 查找结点 求二叉树的高度 输出二叉树 //二叉树节点结构体定义 structTreeNode{ intval; TreeNode*left; TreeNode*right; TreeNode(intx):val(x),left(NULL),right(NULL){} }; 创建二叉树 //创建二叉树函数(简单示例,手动构建) TreeNode*create
36 12
|
12天前
|
C++
【C++数据结构——树】二叉树的性质(头歌实践教学平台习题)【合集】
本文档介绍了如何根据二叉树的括号表示串创建二叉树,并计算其结点个数、叶子结点个数、某结点的层次和二叉树的宽度。主要内容包括: 1. **定义二叉树节点结构体**:定义了包含节点值、左子节点指针和右子节点指针的结构体。 2. **实现构建二叉树的函数**:通过解析括号表示串,递归地构建二叉树的各个节点及其子树。 3. **使用示例**:展示了如何调用 `buildTree` 函数构建二叉树并进行简单验证。 4. **计算二叉树属性**: - 计算二叉树节点个数。 - 计算二叉树叶子节点个数。 - 计算某节点的层次。 - 计算二叉树的宽度。 最后,提供了测试说明及通关代
37 10
|
12天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
37 2
|
26天前
|
数据库
数据结构中二叉树,哈希表,顺序表,链表的比较补充
二叉搜索树,哈希表,顺序表,链表的特点的比较
数据结构中二叉树,哈希表,顺序表,链表的比较补充
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
87 5
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
82 1
|
2月前
|
C语言
【数据结构】栈和队列(c语言实现)(附源码)
本文介绍了栈和队列两种数据结构。栈是一种只能在一端进行插入和删除操作的线性表,遵循“先进后出”原则;队列则在一端插入、另一端删除,遵循“先进先出”原则。文章详细讲解了栈和队列的结构定义、方法声明及实现,并提供了完整的代码示例。栈和队列在实际应用中非常广泛,如二叉树的层序遍历和快速排序的非递归实现等。
284 9
|
2月前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
44 1