数据结构:二叉树(链式结构)

news2024/9/22 7:24:48

文章目录

  • 1. 二叉树的链式结构
  • 2. 二叉树的创建和实现相关功能
    • 2.1 创建二叉树
    • 2.2 二叉树的前,中,后序遍历
      • 2.2.1 前序遍历
      • 2.2.2 中序遍历
      • 2.2.3 后序遍历
    • 2.3 二叉树节点个数
    • 2.4 二叉树叶子结点个数
    • 2.5 二叉树第k层结点个数
    • 2.6 二叉树的深度/高度
    • 2.7 二叉树查找值为x的结点
    • 2.8 层序遍历
    • 2.9 判断二叉树是否为完全二叉树
    • 2.10 二叉树的销毁
  • 3. 源代码

1. 二叉树的链式结构

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成:数据域和左右指针域左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,三叉链在结构上比二叉链多了一个指向父节点的指针域。

请添加图片描述
在这里先使用二叉链来实现二叉树

2. 二叉树的创建和实现相关功能

2.1 创建二叉树

用链表来实现二叉树,每个链表结点都由一个数据域和左右指针域组成

//定义二叉树的链式结构
//二叉树结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode {
	BTDataType data;//存储数据
	struct BinaryTreeNpde* left;//指向左孩子结点的指针
	struct BinaryTreeNode* right;//指向右孩子结点的指针
}BTNode;

接下来我们来实现创建节点的函数:

首先使用malloc函数创建一个节点大小的空间,如果创建失败就打印错误信息,创建成功则把数据存储在新节点的数据域中,再将新节点的左右孩子指针指向空,最后返回新节点即可

//创建二叉树新节点
BTNode* buyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->left = newnode->right = NULL;
	return newnode;
}

下面我们来创建一棵如图所示的二叉树
在这里插入图片描述

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

2.2 二叉树的前,中,后序遍历

下面来简单介绍一下前,中,后序遍历的规则
在这里插入图片描述
请添加图片描述
下面来根据上面所示的二叉树进行前,中,后序遍历

2.2.1 前序遍历

前序遍历就是先打印根节点的值,再遍历根节点的左子树,最后遍历根节点的右子树,也就是根左右

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

根据以上代码:进入函数先打印根节点存储的值,再递归左子树,左子树递归完后再递归右子树。不要忘了,如果遇到空节点记得要返回。

前序遍历的步骤

  1. 打印根节点的值为1
  2. 递归左子树,创建根节点左孩子节点2的函数栈帧
  3. 打印节点2的值为2,创建节点2的左孩子节点4的函数栈帧
  4. 打印节点4的值为4,创建节点4的左孩子节点的函数栈帧
  5. 节点4的左孩子节点为空,返回节点4的函数栈帧
  6. 创建节点4的右孩子节点的函数栈帧
  7. 节点4的右孩子节点为空,返回节点4的函数栈帧
  8. 节点4的函数栈帧被销毁,返回节点2的函数栈帧
  9. 创建节点2的右孩子节点5的函数栈帧
  10. 打印节点5的值为5,创建节点5的左孩子节点的函数栈帧
  11. 节点5的左孩子节点为空,返回节点5的函数栈帧
  12. 创建节点5的右孩子节点的函数栈帧
  13. 节点5的右孩子节点为空,返回节点5的函数栈帧
  14. 节点5的函数栈帧被销毁,返回节点2的函数栈帧
  15. 节点2的函数栈帧被销毁,返回根节点的函数栈帧
  16. 创建根节点的右孩子节点3的函数栈帧
  17. 打印节点3的值为3,创建节点3的左孩子节点6的函数栈帧
  18. 打印节点6的值为6,创建节点6的左孩子节点的函数栈帧
  19. 节点6的左孩子节点为空,返回节点6的函数栈帧
  20. 创建节点6的右孩子节点的函数栈帧
  21. 节点6的右孩子节点为空,返回节点6的函数栈帧
  22. 节点6的函数栈帧被销毁,返回节点3的函数栈帧
  23. 创建节点3的右孩子节点的函数栈帧
  24. 节点3的右孩子节点为空,返回节点3的函数栈帧
  25. 节点3的函数栈帧被销毁,返回根节点的函数栈帧
  26. 根节点的函数栈帧被销毁

所以前序遍历的结果为:1 2 4 5 3 6

中序遍历和后序遍历与前序遍历的思路一样,只是打印节点的值和递归左右子树的顺序不同而已

2.2.2 中序遍历

思路:先遍历根节点的左子树,再打印根节点的值,最后遍历根节点的右子树,也就是左根右

中序遍历的结果:4 2 5 1 6 3

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

2.2.3 后序遍历

思路:先遍历根节点的左子树,再遍历根节点的右子树,最后打印根节点的值,也就是左右根

后序遍历的结果:4 5 2 6 3 1

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

2.3 二叉树节点个数

思路先递归根节点的左子树,再递归根节点的右子树,如果递归到空节点就返回0,最后返回左子树节点个数和右子树节点个数的和再加一

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

2.4 二叉树叶子结点个数

思路:第一种情况:如果递归到的当前节点为空就返回0,第二种情况:如果节点的左右子树为空时说明该节点为叶子节点则返回1,第三种情况:如果递归到的节点既不是空又不是叶子节点,则继续递归该节点的左右子树,即返回该节点左右子树的叶子节点 return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right)

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

2.5 二叉树第k层结点个数

思路因为根节点是第一层,所以每次向下遍历时将k减一,当k=1时当前节点就是在第k层,返回1即可,所以只需一直递归节点的左右子树,每次递归节点的左右子树时还要让k减一。当递归到的节点为空时,只需返回0即可,要先判断节点为不为空,如果不为空再判断当前节点是不是在第k层。

//二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

2.6 二叉树的深度/高度

思路因为二叉树的左右子树的高度可能不一样,所以要分开递归二叉树的左右子树,然后再取最大值即可。当递归到空节点时返回0,否则继续递归当前节点的左右子树,最后返回左右子树深度的最大值再加一(因为当前的根节点也是一层)

//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDepth = BinaryTreeDepth(root->left);
	int rightDepth = BinaryTreeDepth(root->right);
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

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

思路先遍历根节点的左子树,如果找到了值为x的节点就返回该节点的地址,右子树也无需再遍历了,如果没有找到再遍历右子树,如果找到了就返回该节点的地址,没有找到则返回空。再遍历的过程中,先判断节点是否为空,如果为空就返回空,不为空的话再判断该节点的值是不是x,如果是就返回该节点的地址,如果不是就继续遍历该节点的左右子树。

//二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	BTNode* leftfind = BinaryTreeFind(root->left, x);
	if (leftfind)
	{
		return leftfind;
	}
	BTNode* rightfind = BinaryTreeFind(root->right, x);
	if (rightfind)
	{
		return rightfind;
	}
	return NULL;
}

2.8 层序遍历

这里需要借助队列,不熟悉的可以看一下数据结构—队列

层序遍历是指从根节点开始一层一层遍历二叉树,从上至下,从左至右,依次访问节点,如下图,该二叉树的层序遍历结果为:1 2 3 4 5 6

请添加图片描述
使用队列这个数据结构来实现层序遍历,队列的特点是先进先出首先将根节点放入队列中,再将根节点出队,最后将根节点的左右孩子节点入队。将根节点的左孩子2出队,然后将根节点的左孩子2的左右孩子节点入队,以此类推……一直到队列为空

在这里插入图片描述

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

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

思路同样还是借助队列这个数据结构,与层序遍历不同的是,当节点的左右孩子节点为空时也要进行入队操作,当队头为空时,就退出循环,然后还需要判断队列里有没有不为空的节点,如果有说明二叉树不为完全二叉树,如果没有说明二叉树为完全二叉树

//判断二叉树是否为完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	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)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

2.10 二叉树的销毁

思路因为要销毁整个二叉树包括根节点,所以这里传递的是二级指针去接收一级指针的地址,这样就实现了形参改变实参。先销毁根节点的左子树和右子树,也就是递归到叶子节点开始销毁,然后往上一层一层地进行销毁,最后再销毁根节点。

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

3. 源代码

Tree.h头文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

//定义二叉树的链式结构
//二叉树结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode {
	BTDataType data;//存储数据
	struct BinaryTreeNpde* left;//指向左孩子结点的指针
	struct BinaryTreeNode* right;//指向右孩子结点的指针
}BTNode;

//创建二叉树新节点
BTNode* buyNode(BTDataType x);
//创建一个二叉树
BTNode* CreateTree();
//前序遍历
void PreOrder(BTNode* root);
//中序遍历
void InOrder(BTNode* root);
//后序遍历
void PostOrder(BTNode* root);
//二叉树结点个数
int BinaryTreeSize(BTNode* root);
//二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root);
//二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root);
//二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
//二叉树销毁
void BinaryTreeDestory(BTNode** root);
//层序遍历
void LevelOrder(BTNode* root);
//判断二叉树是否为完全二叉树
bool BinaryTreeComplete(BTNode* root);

Tree.c源文件

#include "Tree.h"
#include "Queue.h"
//创建二叉树新节点
BTNode* buyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->left = newnode->right = NULL;
	return newnode;
}
//前序遍历
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}
//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->data);
}
//二叉树结点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}
//二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
//二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftDepth = BinaryTreeDepth(root->left);
	int rightDepth = BinaryTreeDepth(root->right);
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
//二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	BTNode* leftfind = BinaryTreeFind(root->left, x);
	if (leftfind)
	{
		return leftfind;
	}
	BTNode* rightfind = BinaryTreeFind(root->right, x);
	if (rightfind)
	{
		return rightfind;
	}
	return NULL;
}
//二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestory(&((*root)->left));
	BinaryTreeDestory(&((*root)->right));
	free(*root);
	*root = NULL;
}
//层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		printf("%d ", front->data);
		QueuePop(&q);
		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}
	}
	QueueDestroy(&q);
}
//判断二叉树是否为完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	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)
		{
			QueueDestroy(&q);
			return false;
		}
	}
	QueueDestroy(&q);
	return true;
}

test.c源文件

#include "Tree.h"

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

void BinaryTreeTest01()
{
	BTNode* node1 = CreateTree();
	PreOrder(node1);
	printf("\n");
	InOrder(node1);
	printf("\n");
	PostOrder(node1);
	printf("\n");
	printf("%d\n", BinaryTreeSize(node1));
	printf("%d\n", BinaryTreeLeafSize(node1));
	printf("第%d层结点个数为:%d\n", 3, BinaryTreeLevelKSize(node1, 3));
	printf("%d\n", BinaryTreeDepth(node1));
	if (BinaryTreeFind(node1, 10) == NULL)
	{
		printf("没有找到\n");
	}
	else
	{
		printf("找到了\n");
	}
	LevelOrder(node1);
	printf("\n");
	printf("%s\n", BinaryTreeComplete(node1) == true ? "是完全二叉树" : "不是完全二叉树");
	BinaryTreeDestory(&node1);
}
int main()
{
	BinaryTreeTest01();
	return 0;
}

对以上内容有不同看法的欢迎来讨论,希望对大家的学习有帮助,多多支持哦!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1964781.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vitis HLS 完美嵌套循环通过 m_axi 接口读取DDR 的迭代次数细粒度控制实验 — 问题描述

1 自媒体账号 目前运营的自媒体账号如下&#xff1a; 哔哩哔哩 【雪天鱼】: 雪天鱼个人主页-bilibili.comCSDN 【雪天鱼】: 雪天鱼-CSDN博客 QQ 学习交流群 FPGA科研硕博交流群 910055563 (进群有一定的学历门槛&#xff0c;长期未发言会被请出群聊&#xff0c;主要交流FPG…

str字符串常量,字符指针char * str的存储方式,以及如何赋值的

在使用字符指针时&#xff0c;第一种为通常的情况。 这次主要关注第二种情况&#xff1a;把字符串赋值给字符指针变量&#xff0c;pa中存储的不是这串字符&#xff0c;而是字符串的首字符的地址。 abcdef作为一个常量字符串程序会把其放在一个单独的内存区域&#xff0c;pa存储…

C++ Primer 总结索引 | 第十七章:标准库特殊设施

仍有一些标准库设施在很多应用中都是有用的&#xff1a;tuple、bitset、正则表达式以及随机数。还将介绍一些附加的I/O库功能&#xff1a;格式控制、未格式化I/O和随机访问 1、tuple 类型 1、tuple 是类似 pair 的模板。不同 tuple 类型的成员类型也不同&#xff0c;但一个 t…

基于SpringBoot+Vue的在线政务服务中心(带1w+文档)

基于SpringBootVue的在线政务服务中心(带1w文档) 本在线政务服务中心管理系统应用在线政务服务中心&#xff0c;数据库采用的是Mysql数据库&#xff0c;并且选择了java语言和SpringBoot框架进行开发项目&#xff0c;在项目开发过程中&#xff0c;实现了系统功能模块的安全性、实…

基于SpringBoot+Vue的来访管理系统(带1w+文档)

基于SpringBootVue的来访管理系统(带1w文档) 本系统为了数据库结构的灵活性所以打算采用MySQL来设计数据库[1]&#xff0c;而java技术[2]&#xff0c; B/S架构则保证了较高的平台适应性。文中主要是讲解了该系统的开发环境、要实现的基本功能和开发步骤&#xff0c;并主要讲述了…

删除链表的倒数第N个结点(LeetCode)

题目 给你一个链表&#xff0c;删除链表的倒数第个结点&#xff0c;并且返回链表的头结点。 示例1&#xff1a; 输入&#xff1a;&#xff0c; 输出&#xff1a; 示例2&#xff1a; 输入&#xff1a;&#xff0c; 输出&#xff1a; 示例3&#xff1a; 输入&#xff1a;&#x…

HCL实验1:两台PC通过交换机ping通

2台PC机器的Ip地址必须在同一子网 PC_2的ip地址和子网掩码配置如下 PC_3的ip地址和子网掩码配置如下 将接口管理启用 在PC_2的主机上ping PC_3的ip

万科云城 科技驱动的产城融合未来开放式智慧园区

随着科技的飞速发展&#xff0c;产城融合正成为推动城市发展的新引擎&#xff0c;而智慧园区作为产城融合建设的承载体&#xff0c;通过云、边、端等新型基础设施的不断完善&#xff0c;将生产、生活等功能板块有机结合&#xff0c;打破物理边界&#xff0c;重塑科技空间与服务…

人工智能已经到来,下一步会是什么?

人工智能 (AI) 一词诞生于 1955 年&#xff0c;当时一小群科学家游说洛克菲勒基金会资助达特茅斯研讨会&#xff0c;这是一项为期两个月的项目&#xff0c;其目的是“找到如何让机器使用语言、形成抽象和概念、解决现在只能由人类解决的各种问题并自我完善”。 人工智能的快速…

C++ 二叉树-递归与层序遍历

二叉树的题目根据不同的题目特点需要用不同的递归算法或者层序遍历实现。 递归三要素 根据题目要求&#xff1a;确定递归函数的参数和返回值&#xff1b;根据题目要求&#xff1a;确定递归函数的终止返回条件&#xff1b;根据题目要求&#xff1a;确定单层的递归逻辑。 层序…

系统架构设计师体系(高级)——开篇

哈哈&#xff0c;架构体系终于开篇了&#xff01;需要说明的是软考架构偏向于技术层面&#xff0c;对数据、业务和应用方向需要再开设新专栏。同时&#xff0c;笔者编写的内容大多基于培训、阅读和其他途径的综合整理&#xff0c;并不代表已经具有高级架构知识体系。希望读者可…

DjangoRF-10-过滤-django-filter

1、安装pip install django-filter https://pypi.org/ 搜索django-filter基础用法 2、进行配置 3、进行内容调试。 4、如果碰到没有关联的字段。interfaces和projects没有直接关联字段&#xff0c;但是interface和module有关联&#xff0c;而且module和projects关联&#x…

程序员转型AI大模型好转吗?成功率高吗?

前言 在程序员圈子中&#xff0c;技术转型近年来一直是热门话题。随着AI技术的迅猛发展&#xff0c;优秀人才短缺&#xff0c;程序员向AI大模型转型似乎成为了一条通往职场先机的路径。但是&#xff0c;这条转型之路是否容易走&#xff0c;成功率又如何呢&#xff1f; 一、程…

刷题了: 110.平衡二叉树 | 257. 二叉树的所有路径 |404.左叶子之和 | 222.完全二叉树的节点个数

110.平衡二叉树 文章讲解:https://programmercarl.com/0110.%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91.html 视频讲解:https://www.bilibili.com/video/BV1Ug411S7my/?spm_id_from333.788&vd_sourcee70917aa6392827d1ccc8d85e19e8375 题目链接:https://leetcode.cn…

MySQL从jsonarray获取某个字段的所有数据

表结构。表里的order_goods_info_vo_list是jsonarray字段 CREATE TABLE pdd_charge_back_bantuo (id int(11) NOT NULL AUTO_INCREMENT,shopname varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 店铺名,charge_back_sn varchar(64) COLLATE utf8mb4_bin DEFAULT NULL …

8. Spring Ai之入门到精通(超级详细)

简介 2024年5月30号Spring AI 的 1.0.0 里程碑 1 版本发布。表明版本已正在巩固&#xff0c;并且大部分主要错误和问题已经解决&#xff0c;API基本已确定&#xff0c;不会发生很大的变化。 在与大模型集成方面&#xff0c;继LangChain4j之后&#xff0c;又一重大的框架诞生。标…

捷径,这世上有没有捷径

Q&#xff1a;大师&#xff0c;这个世界上有没有捷径&#xff1f; A&#xff1a;有呀&#xff0c;有捷径呀 Q&#xff1a;大师&#xff0c;那我要怎么走&#xff1f; A&#xff1a;你错啦&#xff0c;不要想着走捷径&#xff0c;因为捷径不是用来走的&#xff0c;捷径是用来飞的…

计算机网络03

文章目录 重传机制超时重传快速重传SACK 方法Duplicate SACK 滑动窗口流量控制操作系统缓冲区与滑动窗口的关系窗口关闭糊涂窗口综合症 拥塞控制慢启动拥塞避免算法拥塞发生快速恢复 如何理解是 TCP 面向字节流协议&#xff1f;如何理解字节流&#xff1f;如何解决粘包&#xf…

设计界的福音:Figma中文官网,你不知道的秘密

Figma是一个基于浏览器的协作式 UI 设计工具&#xff0c;从推出至今受到 越来越多UI设计师的青睐。Figma可以在所有主流操作系统中使用&#xff0c;无论你是Mac还是Windows&#xff0c;都可以运行。无需本地保存&#xff0c;在线多人协作&#xff0c;这样轻量化的工作模式深受大…

【秋招突围】2024届秋招笔试-OPPO笔试题-第一套-三语言题解(Java/Cpp/Python)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新 OPPO 春秋招笔试题**汇总&#xff5e; &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; ✨ 笔试合集传送们 -> &#x1f9f7;春秋招笔试合集 &#x1f380; 01.K小姐的快…