NzN的数据结构--二叉树part2

        上一章我们介绍了二叉树入门的一些内容,本章我们就要正式开始学习二叉树的实现方法,先三连后看是好习惯!!!

目录

一、二叉树的顺序结构及实现

1. 二叉树的顺序结构

2. 堆的概念及结构

3. 堆的实现

3.1 堆的创建

3.2 堆的插入

3.3 向下调整算法

3.4 堆的删除

3.5 总体代码实现

4. 堆操作的时间复杂度

二、堆的应用

1. 堆排序

2. TOP-K问题

三、二叉树链式结构的实现

1. 前置说明

2. 二叉树的遍历

2.1 前/中/后序遍历

2.2 层序遍历 

2.3 节点个数以及深度等

3. 二叉树的销毁


一、二叉树的顺序结构及实现

1. 二叉树的顺序结构

        普通的二叉树不适合用数组来存储,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储。

2. 堆的概念及结构

        如果有一个关键码的集合  ={, ,…,},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: ),则称为小堆(或大堆)。

        大堆(大根堆):根节点最大;所有父亲都≥孩子

        小堆(小根堆):根节点最小;所有父亲都≤孩子

        堆的性质:

  • 堆中某个节点的值总是≥(或≤)其父节点的值,成为大堆(或小堆)
  • 堆总是一棵完全二叉树

注意:堆在数组里不是有序的,小()堆可以帮我们找到最小()值,即找到根节点。

3. 堆的实现

3.1 堆的创建

        我们给出一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,我们怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。

3.2 堆的插入

        先插入一个10到数组的尾上,再进行向上调整算法,直到满足堆。

3.3 向下调整算法

        我们给出一个数组,逻辑上看做一棵完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。

3.4 堆的删除

        删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。

3.5 总体代码实现

        先在头文件中对相关功能接口进行声明:

typedef int HPDataType;
//数组实现
typedef struct Heap
{
	HPDataType* a;//底层就是一个数组
	int size;
	int capacity;
}HP;
//堆的初始化和销毁
void HeapInit(HP* php);
void HeapInitArray(HP* php, HPDataType* a, int n);
void HeapDestroy(HP* php);
//向上调整算法
void AdjustUp(HPDataType* a, int child);
//往堆中插入数据
void HeapPush(HP* php, HPDataType x);
//向下调整算法
void AdjustDown(HPDataType* a, int size, int parent);
//删除堆顶(根节点)
void HeapPop(HP* php);
//输出根节点
HPDataType HeapTop(HP* php);
//计算堆的大小
size_t HeapSize(HP* php);
//判断堆是否为空
bool HeapEmpty(HP* php);
//堆排序
void HeapSort(int* a, int n);
//TOP-K问题
void PrintTopK(int* a, int n, int k);

        下面是接口的具体实现:

//堆的初始化和销毁
void HeapInit(HP* php)
{
	assert(php);
	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}

void HeapDestroy(HP* php)
{
	assert(php);
	free(php->a);
	php->a = NULL;
	php->size = php->capacity = 0;
}

//将交换功能封装成Swap函数,以便复用
void Swap(HPDataType* p1, HPDataType* p2)
{
	HPDataType tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

//以小堆为例
void AdjustUp(HPDataType* a, int child)
{
	int parent = (child - 1) / 2;
	//确保不会移动根节点(因为根节点的索引为0,没有父节点)
	while (child > 0)
	{
		//孩子 < 父亲,就要交换
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			child = parent;//把父亲的位置给孩子
			parent = (child - 1) / 2;//再算新的父亲
		}
		else
		{
			break;
		}
	}
}

//往堆中插入数据
void HeapPush(HP* php, HPDataType x)
{
	assert(php);
	//空间不够需要扩容
	if (php->size == php->capacity)
	{
		//初始化时capacity=0,所以要先给他4个空间
		int newCapacity = php->capacity == 0 ? 4 : php->capacity * 2;
		HPDataType* tmp = (HPDataType*)realloc(php->a, newCapacity * sizeof(HPDataType));
		if (tmp == NULL)
		{
			perror("realloc");
			return;
		}
		//把原来的数组和容量更新成扩容之后的
		php->a = tmp;
		php->capacity = newCapacity;
	}
	php->a[php->size] = x;//在尾部插入数据
	php->size++;//插入一个数据后,size要+1
	//插入之后可能就不是堆了,通过向上调整算法把它变成堆
	AdjustUp(php->a, php->size - 1);
}

//向下调整算法
void AdjustDown(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		//默认左孩子小,假设错误就更新一下
		if (child + 1 < size && a[child + 1] < a[child])//右孩子存在&&右孩子小于左孩子
		{
			++child;//child是左孩子,+1就是右孩子
		}

		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//删除堆顶(根节点)
void HeapPop(HP* php)
{
	assert(php);
	assert(php->size > 0);//至少要有一个节点

	//把堆顶的数据跟数组的尾元素交换位置
	//此时删除堆顶就变成了删除数组的尾元素
	Swap(&php->a[0], &php->a[php->size - 1]);
	php->size--;
	//删除操作就是控制size来完成的
	//其实我们并不是把这个数据删除,而是把他反复在最后就不用管它了
	//size-1后,想要访问这个数据就变成了数组越界访问
	AdjustDown(php->a, php->size, 0);
}

//输出根节点
HPDataType HeapTop(HP* php)
{
	assert(php);
	assert(php->size > 0);
	return php->a[0];
}

//计算堆的大小
size_t HeapSize(HP* php)
{
	assert(php);
	return php->size;
}

//判断堆是否为空
bool HeapEmpty(HP* php)
{
	assert(php);
	return php->size == 0;
}

4. 堆操作的时间复杂度

        因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来就是近似值,多几个节点不影响最终结果):

       插入数据时间消耗主要在向上调整部分,最好情况就是不进行调整,最差情况就是调整树的高度次,因此插入数据的时间复杂度为

       删除数据时间消耗主要在向下调整部分,最好情况就是不进行调整,最差情况就是调整树的高度次,因此删除数据的时间复杂度为

//按照数组来初始化
void HeapInitArray(HP* php, HPDataType* a, int n)
{
	assert(php);
	php->a = (HPDataType*)malloc(sizeof(HPDataType) * n);
	if (php->a == NULL)
	{
		perror("realloc");
		return;
	}
	memcpy(php->a, a, sizeof(HPDataType) * n);//把数据放到堆上
	php->size = n;
	php->capacity = n;

	//建堆

	//模拟向上调整,理解为数据插入,时间复杂度O(N*logN)
	//for (int i = 1; i < php->size; i++)
	//{
	//	AdjustUp(php->a, i);
	//}
	//第二层最多向上调整1次,第三层最多向上调整2次……,最后一层最多向上调整h-1次
	//假设累计向上调整F(h)次,F(h)=2^1*1+2^2*2+…+2^(h-1)*(h-1)=2^h*(h-2)+2
	//把F(h)转换成F(N),h=log(N+1),因此F(N)=(N+1)*(log(N+1)-2)+2≈N*logN


	//模拟向下调整,时间复杂度O(N)
	//从倒数的第一个非叶子结点开始调整(最后一个节点的父亲),倒着往上调
	//最后一个节点的下标是php->size - 1,i求他的父亲然后开始倒着调整
	for (int i = (php->size - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(php->a, php->size, i);
	}
	//假设累计向下调整F(h)次,F(h)=2^(h-2)*1+2^(h-3)*2+…+2^0*(h-1)
	//F(N)=N-log(N+1)≈N
}

        对于向上调整,满二叉树最后一层结点数占整个树的一半,结点数量多的层,调整次数也多。而向下调整正好相反,结点数量多的调整次数少。因此两种方法时间复杂度相差较大,我们优先选择向下调整建堆。

二、堆的应用

1. 堆排序

void HeapSort(int* a, int n) 
{
	HP hp;
	HeapInitArray(&hp, a, n);
	int i = 0;
	while (!HeapEmpty(&hp))
	{
		a[i++] = HeapTop(&hp);//将堆顶赋给a[0]
		HeapPop(&hp);//删除堆顶元素,这样堆中第二大/小的元素就会被移动到堆顶
	}
	HeapDestroy(&hp);
}

        上面这种写法有两大缺陷,首先就是进行堆排序之前需要先创建堆的各种相关算法,其次就是空间复杂度为

        堆排序即利用堆的思想来进行排序,总共分为两个步骤:

        [1] 建堆

  •         升序:建大堆
  •         降序:建小堆

       [2]  利用堆删除思想来进行排序

        建堆和堆删除中都用到了向下调整,因此通过向下调整,就可以完成堆排序。

//大堆的向下调整算法
void AdjustDown(HPDataType* a, int size, int parent)
{
	int child = parent * 2 + 1;
	while (child < size)
	{
		//默认左孩子大,假设错误就更新一下  
		if (child + 1 < size && a[child] < a[child + 1]) //右孩子存在且右孩子大于左孩子  
		{
			++child; // child原本是左孩子,+1变成右孩子  
		}

		//如果子节点大于父节点则交换 
		if (a[child] > a[parent])
		{
			Swap(&a[child], &a[parent]);
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

//升序建大堆,降序建小堆
//建小堆如果想要升序,堆顶元素在对应位置,剩余元素重新建小堆,时间复杂度大大增加
void HeapSort(int* a, int n)
{
	//对数组直接建堆
	for (int i = (n - 1 - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}

	// O(N*logN)
	int end = n - 1;
	while (end > 0)
	{
		Swap(&a[0], &a[end]);//上面建的大堆,根节点最大,把大的数据往后放
		AdjustDown(a, end, 0);//新的根节点可能会破坏大堆性质,需要向下调整
		end--;
	}
}

 注意:我们需要根据升序或降序的要求,对向下调整算法进行修改。

2. TOP-K问题

        TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素。

        对于Top-K问题,最容易想到的方法就是排序,但是如果数据量非常大,排序就不可取了(可能数据不能一口气全部加载到内存中)。

        最佳的方式就是用堆来解决,基本思路如下:

        [1] 用数据集合中前K个元素来建堆

  •         求前k个最大的元素,则建小堆
  •         求前k个最小的元素,则建大堆

        [2] 用剩余的N-K个元素依次与堆顶比较,不满足则替换堆顶元素

        将剩余N-K个元素依次与堆顶元素比较之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

        这种方法的时间复杂度是

//以求前K个最大的数据为例,则需要建小堆
void PrintTopK(int* a, int n, int k)
{
	HP php;
	HeapInit(&php);
	//数组中前k个元素来建堆
	for (int i = 0; i < k; ++i) 
	{
		HeapPush(&php, a[i]);
	}
	//用剩余的n-k个元素依次与堆顶比较
	for (int i = k; i < n; ++i) 
	{
		if (a[i] > HeapTop(&php)) //当前元素>堆顶,就要让他进堆
		{ 
			HeapPop(&php); //移除当前堆顶
			HeapPush(&php, a[i]); //将新的元素插入堆中
		}
	}
	for (int i = 0; i < k; ++i) {
		printf("%d ", php.a[i]);
	}
	printf("\n");
	HeapDestroy(&php);
}

三、二叉树链式结构的实现

1. 前置说明

        在学习二叉树的基本操作前,需先创建一棵二叉树,然后才能学习其相关操作。由于现在对二叉树结构掌握还不够深入,因此在此处手动快速创建一棵简单的二叉树,快速学习二叉树操作,等后面再来研究二叉树真正的创建方式。

        回顾下二叉树的概念,二叉树是:

  • 空树
  • 非空:根节点,根节点的左子树、根节点的右子树组成的

        从概念中可以看出,二叉树是递归定义的,因此后序基本操作中基本都是按照该概念实现的。

2. 二叉树的遍历

2.1 前/中/后序遍历

        学习二叉树结构,最简单的方式就是遍历。所谓二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。访问结点所做的操作依赖于具体的应用问题。 遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。

        按照规则,二叉树的遍历有:前序/中序/后序的递归结构遍历:

  • 前序遍历(先序遍历):根 左子树 右子树。
  • 中序遍历:左子树 根 右子树。
  • 后序遍历:左子树 右子树 根。
typedef struct BinTreeNode 
{
	struct BinTreeNode* left;
	struct BinTreeNode* right;
	int val;
}BTNode;

//前序遍历
void PreOrder(BTNode* root)
{
	//树为空
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	//树不为空,按照 根 左子树 右子树 的顺序递归打印
	printf("%d ", root->val);
	PreOrder(root->left);
	PreOrder(root->right);
}

//中序遍历
void InOrder(BTNode* root)
{
	//树为空
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	//树不为空,按照 左子树 根 右子树 的顺序递归打印
	InOrder(root->left);
	printf("%d ", root->val);
	InOrder(root->right);
}

//后序遍历
void PostOrder(BTNode* root)
{
	//树为空
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	//树不为空,按照 左子树 右子树 根 的顺序递归打印
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%d ", root->val);
}

        前序遍历递归图解:

2.2 层序遍历 

        自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

       层序遍历的实现需要借助队列(先进先出),实现思想是上一层带下一层。

void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	//先入根节点
	if (root)
		QueuePush(&q, root);

	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->val);
		//带入下一层
		if (front->left)
			QueuePush(&q, front->left);

		if (front->right)
			QueuePush(&q, front->right);
	}
	printf("\n");
	QueueDestroy(&q);
}

2.3 节点个数以及深度等

//求树的结点个数
static int size = 0;//定义成全局变量,每次调用前初始化为0
int TreeSize(BTNode* root)
{

	if (root == NULL)
		return 0;
	else
		++size;
	TreeSize(root->left);
	TreeSize(root->right);
	return size;
}

       但是这种写法会出现线程安全的风险,可以改成给函数传size的指针或者依靠分治递归思想(左子树返回的结点个数+右子树返回的结点个数+1,通过后序遍历)。

//求树的结点个数
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
//求树的深度
int TreeDepth(BTNode* root)
{
	if (root == NULL)
		return 0;
	//左子树和右子树分别计算深度,取最大的深度+1(根节点)
	int leftDepth = TreeDepth(root->left);
	int rightDepth = TreeDepth(root->right);
	return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
int TreeDepth(BTNode* root)
{
	if (root == NULL)
		return 0;
	return TreeDepth(root->left) > TreeDepth(root->right) ? TreeDepth(root->left) + 1 : TreeDepth(root->right) + 1;
	//这种写法看似与上面的写法相差不大,但实际上这个写法的时间复杂度大打折扣
	//通过leftDepth和rightDepth会记录左右子树的深度,return时不需要再次计算,时间复杂度为O(N)
	//而这种写法每次使用TreeDepth(root->left)或TreeDepth(root->right)都需要重新计算一次
	//时间复杂度是一个等比数列和,根节点的找次其实是第二层节点找2次,是第三层找4次……
	//最后算到时间复杂度为O(2^N)
}
//求第k层的节点个数
//当前树的第k层节点个数=左子树的第k-1层节点个数+右子树的第k-1层节点个数
int TreeKLevel(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
		return 0;
	//只有根节点
	if (k == 1)
		return 1;
	//k>1,说明第k层在子树里
	return TreeKLevel(root->left, k - 1) + TreeKLevel(root->right, k - 1);
}
//查找x所在的节点(找到1个就返回)
BTNode* TreeFind(BTNode* root, int x)
{
	if (root == NULL)
		return NULL;
	if (root->val == x)
		return root;
	//先在左子树找,没找到再去右子树找
	//如果要找两次,推荐用变量来接收
	BTNode* ret1 = TreeFind(root->left, x);
	if (ret1)
		return ret1;
	BTNode* ret2 = TreeFind(root->right, x);
	if (ret2)
		return ret2;
	return NULL;
}

3. 二叉树的销毁

void TreeDestroy(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestroy(root->left);
	TreeDestroy(root->right);
	free(root);
	//root = NULL;//这里置空对形参修改,实参不改变
	//但是想要修改root就需要二级指针,非常麻烦
	//因此可以调用完TreeDestroy函数后,手动将root置为NULL
}

        以上就是本文的全部内容,这个地方非常难理解,大家要注意看每段代码的注释部分,后面需要勤加练习,熟练掌握这些算法!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

90天玩转Python—10—基础知识篇:函数详解

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…

循环单链表算法库

学习贺老师数据结构 数据结构之自建算法库——循环单链表_循环单链表 csdn-CSDN博客​​​​​​ 整理总结出的循环单链表算法库 v1.0 : 基本实现功能 v2.0(2024.4.6): 修复Delete_SpecificLocate_CyclicList()删除节点函数bug,添加验证删除节点是否超范围判断 目录 1.主要功能…

Blender2.83 下载地址及安装教程

Blender是一款开源的3D计算机图形软件&#xff0c;广泛应用于动画制作、游戏开发、建模、渲染等领域。它提供了一套强大的工具和功能&#xff0c;让用户能够进行三维建模、动画制作和视觉效果的创作。 Blender支持多种文件格式的导入和导出&#xff0c;使用户能够与其他软件进…

【Linux源码学习】(一)源码下载、解压说明

目录 一、Linux源码下载地址 二、使用7z解压 一、Linux源码下载地址 官网下载&#xff1a;The Linux Kernel Archives 我们可以到这个地址下载各种版本的压缩包&#xff1a;即上图对应的http网址。 Index of /pub/ 选择Linux 找内核代码 这里直接选择最新的6.x 然后往下翻&…

《猎灵online》游戏完整源码(源码+客户端+服务端+文档+工具),云盘下载

《猎灵》是一款由国内知名开发运营开发的大型3D魔幻网游&#xff0c;《猎灵》研发团队突破诸多瓶颈&#xff0c;首创“全自由无限制PK”&#xff0c;让玩家拒绝无意义等待&#xff0c;自由作战不受任何束缚&#xff0c;真正的实现想战就战&#xff0c;游戏创建了六界神魔乱斗的…

单调栈用法

文章目录 1. 单调栈1.1 理解单调栈&#xff08;模板&#xff09;1.2 每日温度1.3 子数组的最小值之和1.4 柱状图中最大的矩形1.5 最大矩形1.6 最大宽度坡1.7 去除重复字母 1. 单调栈 单调栈经典的用法&#xff1a; 对每个位置都求&#xff1a; 当前位置的左侧比当前位置的数…

UDP网络程序

上一章中&#xff0c;我们介绍了socket&#xff0c;以及TCP/UDP协议。这一章带大家实现几个UDP协议的网络服务。我们需要一个 服务端和一个客户端。 1.服务端实现 1.1socket函数 #include <sys/types.h> #include <sys/socket.h>int socket(int domain, in…

【JAVA基础篇教学】第六篇:Java异常处理

博主打算从0-1讲解下java基础教学&#xff0c;今天教学第五篇&#xff1a; Java异常处理。 异常处理是Java编程中重要的一部分&#xff0c;它允许开发人员在程序运行时检测和处理各种错误情况&#xff0c;以保证程序的稳定性和可靠性。在Java中&#xff0c;异常被表示为对象&am…

【 书生·浦语大模型实战营】作业(三):“茴香豆” 搭建你的RAG 智能助理

【 书生浦语大模型实战营】学习笔记&#xff08;三&#xff09;&#xff1a;“茴香豆” 搭建你的RAG 智能助理作业 &#x1f389;AI学习星球推荐&#xff1a; GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI…

JVM参数列表

-client :设置JVM使用client模式,特点启动较快(神机不明显(I5/8G/SSD)) -server :设置JVM使用server模式。64位JDK默认启动该模式 -agentlib:libname[options] :用于加载本地的lib -agentlib:hprof :用于获取JVM的运行情况 -agentpath:pathnamep[options] :加载制定路径的本…

PHP01——php快速入门 之 使用phpstudy快速搭建PHP环境

PHP01——php快速入门 之 使用phpstudy快速搭建PHP环境 0. 前言1. 下载小皮面板1.1 下载phpstudy&#xff08;小皮面板&#xff09;1.2 启动、简单访问1.2.1 启动Apache1.2.2 访问1.2.3 访问自定义文件或页面 2. 创建网站2.1 创建网站2.2 可能遇到的问题2.2.1 hosts权限问题&am…

极海APM32电机驱动板记录(二)

文章目录 1、解除写保护2、极海驱动板资源概述3、新建工程4、点灯5、嘀嗒定时器6、中断7、串口打印8、adc读取9、i2c尝试10、定时器测试11、电机驱动pwm测试 上一篇文章算是简单了解了一下极海的板子开发环境吧&#xff0c;结果前几天板子来了&#xff0c;然后发现一个大bug&am…

力扣题目 19:删除链表的倒数第N个节点 【python】

&#x1f464;作者介绍&#xff1a;10年大厂数据\经营分析经验&#xff0c;现任大厂数据部门负责人。 会一些的技术&#xff1a;数据分析、算法、SQL、大数据相关、python 欢迎加入社区&#xff1a; 码上找工作http://t.csdnimg.cn/Q59WX 作者专栏每日更新&#xff1a; LeetCod…

Qt-绘制多边形、椭圆、多条直线

1、说明 所有的绘图操作是在绘图事件中进行。mainwindow.h #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWi…

C++ 类和对象(一)

目录 0.前言 1.面向过程&面向对象 1.1面向过程编程&#xff08;PP&#xff09; 1.2面向对象编程&#xff08;OOP&#xff09; 1.3从C到C 2.类的引入 2.1C语言中的结构体 2.2C中类的引入 2.3结构体与类的区别 2.4为什么引入类 3.类的定义 3.1声明与定义不分离 …

【Java探索之旅】从输入输出到猜数字游戏

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java编程秘籍 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 &#x1f4d1;前言一、输入输出1.1 输出到控制台1.2 从键盘输入 二、猜数字游戏2.1 所需知识&#xff1a…

【动态规划】【01背包】Leetcode 1049. 最后一块石头的重量 II

【动态规划】【01背包】Leetcode 1049. 最后一块石头的重量 II 解法 ---------------&#x1f388;&#x1f388;题目链接&#x1f388;&#x1f388;------------------- 解法 &#x1f612;: 我的代码实现> 动规五部曲 ✒️确定dp数组以及下标的含义 dp[j]表示容量为…

Learn SRP 01

学习链接&#xff1a;Custom Render Pipeline (catlikecoding.com) 使用Unity版本&#xff1a;Unity 2022.3.5f1 1.A new Render Pipeline 1.1Project Setup 创建一个默认的3D项目&#xff0c;项目打开后可以到默认的包管理器删掉所有不需要的包&#xff0c;我们只使用Unit…

陆面、生态、水文模拟与多源遥感数据同化

原文链接&#xff1a;陆面、生态、水文模拟与多源遥感数据同化https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247601198&idx6&sn51b9b26b75c9df1f11dcb9a187878261&chksmfa820dc9cdf584df9ac3b997c767d63fef263d79d30238a6523db94f68aec621e1f91df85f6…

算法——字符串

T04BF &#x1f44b;热门专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享字符串相关算法 如果有不足的或者错误的请您指出! 目录 1.最长公共前缀1.1解析1.2题解 2.最长回文子串2.1解析2.2题解 3.二级制求和3.1解析3.2题解 4.字符串相乘4.1解析4.2…