【C语言】二叉树链式结构的实现,详解

news2024/11/15 13:48:16

0.前言

二叉树的基本操作的实现基本离不开一个思想——分治算法。

分治算法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题相同。递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这样,通过逐步缩小问题的规模,可以显著降低解决问题的复杂度。

1.一颗二叉树的创建

在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。先此处手动快速创建一棵简单的二树,快速进入二叉树操作学习,后面会详细说明二叉树真正的创建方式

一颗二叉树分为根、左子树、右子树,该二叉树根1的左边链接根2,根2的左边链接根3,根1的右边链接根4,根4的左边链接根5,根4的右边链接根6。

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->left = newnode->right = NULL;
	newnode->data = x;
	return newnode;
}
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;
}

2.二叉树的三种遍历方式

掌握二叉树的三种遍历方式非常重要,详细思路可看文章:二叉树的三种遍历,这里只展示代码。

2.1前序遍历

void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{

		return;
	}
	printf("%d ", root->data);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}

2.2中序遍历

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

2.3后序遍历

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

3.二叉树的销毁

基本思路:和后序遍历类似,先销毁根节点的左节点,再销毁根节点的右节点,再销毁根节点。

如果按前序遍历的方式销毁,先释放掉根节点,那就找不到他的左节点和右节点。当然也可以先把要是否掉的根节点存起来,但是相较于后序遍历销毁麻烦。

3.1传一级指针

此处有个缺陷,在函数里面将根节点释放掉后置为空,并不能将实参变为空。也就是形参的改变影响不了实参。我们还需在函数外面将实参置为空。

void BinaryTreePDestory(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreePDestory(root->left);
	BinaryTreePDestory(root->right);
	free(root);
}

3.2传二级指针


此处形参的改变将会影响实参,不需要额外再将实参置空

void BinaryTreePPDestory(BTNode** root)
{
	if (*root==NULL)
	{
		return;
	}
	BinaryTreePPDestory(&((*root)->left));
	BinaryTreePPDestory(&((*root)->right));
	free(*root);
	*root = NULL;
}

4.二叉树节点个数

求二叉树节点个数,通常可以通过递归的方式来实现。递归的基本思想是:对于给定的二叉树,其节点总数等于左子树的节点数加上右子树的节点数,再加上根节点本身(1)。根节点为空是返回0.

int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

5.二叉树叶子节点个数

叶子节点是没有左节点并且没有右节点的节点。

思路:如果当前节点为空返回0,当前节点存在且无左节点和右节点则是叶子节点返回1。如果当前节点不是叶子节点(即它有左子节点或右子节点),则递归地计算其左子树的叶子节点个数和右子树的叶子节点个数。将左子树的叶子节点个数和右子树的叶子节点个数相加,得到的结果即为以当前节点为根的子树的叶子节点总数。

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);
}

6.二叉树第k层节点个数

思路:知道k-1层节点的左右节点一共有多少个就是二叉树第k层节点个数。当前节点为空返回0,当k等于1时说明到达第k层返回1。不等于空,且k > 1说明第k层的节点在子树里面,转换成子问题求解

int BinaryTreeLevelKSize(BTNode* root, int k)
{
    assert(k > 0);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1) 
         + BinaryTreeLevelKSize(root->right, k - 1);
}

7. 二叉树查找值为x的节点

7.1只是判断该值是否在二叉中

当前节点为空返回false,当前节点的值等于x返回true,没有找到则递归到左子树里面找,没找到再去右子树找

bool TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return false;
	if (root->data == x)
		return true;
	return TreeFind(root->left, x) || TreeFind(root->right, x);
}

7.2返回第一个是该值的节点

当前节点为空返回,当前节点的值等于x返回该节点,没有找到则递归到左子树里面找,没找到再去右子树找(这里需要注意的是要先把节点存起来,如果没有存起来则返回的时候不会保留)

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return;
	if (root->data == x)
		return root;
	BTNode* _left = BinaryTreeFind(root->left, x);
	if (_left)
		return _left;
	BTNode* _right = BinaryTreeFind(root->right, x);
	if (_right)
		return _right;
}

8.层序遍历

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



思路:需要借助队列来实现(C语言需要自己实现队列)

首先,检查根节点是否为空,如果不为空,则将其加入队列。然后,进入一个循环,只要队列不为空,就执行以下操作:

从队列中取出一个节点(队首元素),并访问它(打印它的值),再将队列中队头的元素(也就是该节点Pop掉)
如果该节点有左子节点,则将左子节点加入队列。
如果该节点有右子节点,则将右子节点加入队列。

这个过程会按照从上到下、从左到右的顺序遍历二叉树的所有节点。

void BinaryTreeLevelOrder(BTNode* root)
{
	Queue pq;
	QueueInit(&pq);
	if (root)
	{
		QueuePush(&pq, root);
	}
	while (!QueueEmpty(&pq))
	{
		BTNode* front = QueueFront(&pq);
		printf("%d ", front->data);
		QueuePop(&pq);
		if (front->left)
		{
			QueuePush(&pq, front->left);
		}
		if (front->right)
		{
			QueuePush(&pq, front->right);
		}
	}
	printf("\n");
	QueueDestroy(&pq);
}

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

完全二叉树:非空 空。

非完全二叉树:非空 空 非空 空

算法的思路通过层次遍历(广度优先搜索)来判断二叉树是否是完全二叉树。

首先,我们初始化一个队列,并将根节点(如果存在)加入队列中。然后,我们进入一个循环,不断地从队列中取出节点,并尝试将其左右子节点加入队列。如果在某个时刻,我们遇到了一个空节点(即该节点不存在)跳出第一个循环另外判断,不再向队列中添加任何子节点。这是因为,在完全二叉树的定义中,一旦开始遇到空节点,其后的所有节点都应该是空的。

在遍历完所有可能存在的节点后(即所有非空节点的子节点都已经被考虑过),我们再次检查队列。如果此时队列为空,说明我们之前的假设成立,即该二叉树是完全二叉树。如果队列不为空,且队列中的节点不为空,那么说明在之前遇到空节点之后,还有非空节点存在,这与完全二叉树的定义相违背,因此该二叉树不是完全二叉树。

简而言之,这个算法通过层次遍历来检查二叉树是否满足完全二叉树的性质:除了最后一层外,每一层都被完全填满,并且所有节点都尽可能地向左对齐。

bool BinaryTreeComplete(BTNode* root)
{
	Queue pq;
	QueueInit(&pq);
	if (root)
	{
		QueuePush(&pq, root);
	}
	while (!QueueEmpty(&pq))
	{
		BTNode* front = QueueFront(&pq);
		QueuePop(&pq);
		//遇到空以后跳出后续判断
		if (front == NULL)
		{
			break;
		}
		QueuePush(&pq, front->left);
		QueuePush(&pq, front->right);
	}
	//是空出队列,遇见非空则说明不是完全二叉树
	while (!QueueEmpty(&pq))
	{
		BTNode* front = QueueFront(&pq);
		QueuePop(&pq);
		if (front)
		{
			QueueDestroy(&pq);
			return false;
		}
	}
	QueueDestroy(&pq);
	return true;
}

10.二叉树的创建

我们可以借助这道题目来理解:二叉树的遍历

二叉树的形状

按前序遍历的方式创建一颗二叉树,三个参数数组,数组长度,数组下标(初始值设为0)

当*pi>=数组越界或者数组元素等于#时数组下标+1且返回空,

把数组元素赋给节点数据,

递归,让数组的数据按照前序遍历的方式依次赋给节点。

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (*pi >= n || a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->data = a[*pi];
	(*pi)++;

	root->left = BinaryTreeCreate(a, n, pi);
	root->right = BinaryTreeCreate(a, n, pi);
	return root;
}

11.完整代码(包括队列的实现)

11.1BinaryTree.h

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

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;
#include"Queue.h"

BTNode* BuyNode(BTDataType x);
//二叉树的创建
BTNode* CreatBinaryTree();
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);
// 二叉树销毁
void BinaryTreePDestory(BTNode* root);
void BinaryTreePPDestory(BTNode** root);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
bool TreeFind(BTNode* root, BTDataType x);
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

11.2Queue.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdbool.h>
#include<stdlib.h>
#include"BinaryTree.h"
typedef struct BinaryTreeNode* QDataType;
typedef struct QueueNode
{
	QDataType val;
	struct QueueNode* next;
}QNode;
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

//初始化
void QueueInit(Queue* pq);
//销毁
void QueueDestroy(Queue* pq);
//判空
bool QueueEmpty(Queue* pq);
//入队列
void QueuePush(Queue* pq, QDataType x);
//出队列
void QueuePop(Queue* pq);
//取队头
QDataType QueueFront(Queue* pq);
//取队尾
QDataType QueueBack(Queue* pq);
//队列长度
size_t QueueLength(Queue* pq);

11.3Queue.c

#include"Queue.h"
//初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
//销毁
void QueueDestroy(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
//入队列
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);

	//在队尾入,尾插
	//创建新节点
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->val = x;
	newnode->next = NULL;

	//空链表
	if (QueueEmpty(pq))
	{
		pq->phead = pq->ptail = newnode;
	}
	else 
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
//出队列
void QueuePop(Queue* pq)
{
	assert(pq);
	//零个节点
	assert(pq->phead);
	//一个节点
	if (pq->phead->next == NULL)
	{
		free(pq->phead);
		pq->phead = pq->ptail = NULL;
	}
	else
	{
		QNode* next = pq->phead->next;
		free(pq->phead);
		pq->phead = next;
	}
	pq->size--;
}
//判空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->size == 0;
}
//取队头
QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return pq->phead->val;
}
//取队尾
QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(pq->ptail);
	return pq->ptail->val;
}
//队列长度
size_t QueueLength(Queue* pq)
{
	assert(pq);
	return pq->size;
}

11.4BinaryTree.c

#include"BinaryTree.h"

BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->left = newnode->right = NULL;
	newnode->data = x;
	return newnode;
}
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;
}
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	if (*pi >= n || a[*pi] == '#')
	{
		(*pi)++;
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	root->data = a[*pi];
	(*pi)++;

	root->left = BinaryTreeCreate(a, n, pi);
	root->right = BinaryTreeCreate(a, n, pi);
	return root;
}
// 二叉树销毁
//传一级指针
void BinaryTreePDestory(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreePDestory(root->left);
	BinaryTreePDestory(root->right);
	free(root);
}
//传二级指针
void BinaryTreePPDestory(BTNode** root)
{
	if (*root==NULL)
	{
		return;
	}
	BinaryTreePPDestory(&((*root)->left));
	BinaryTreePPDestory(&((*root)->right));
	free(*root);
	*root = NULL;
}
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
// 二叉树叶子节点个数
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)
{
	assert(k > 0);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
// 二叉树查找值为x的节点
bool TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return false;
	if (root->data == x)
		return true;
	return TreeFind(root->left, x) || TreeFind(root->right, x);
}
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return;
	if (root->data == x)
		return root;
	BTNode* _left = BinaryTreeFind(root->left, x);
	if (_left)
	{
		return _left;
	}
	BTNode* _right = BinaryTreeFind(root->right, x);
	if (_right)
	{
		return _right;
	}
		
}
// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{

		return;
	}
	printf("%d ", root->data);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%d ", root->data);
	BinaryTreeInOrder(root->right);
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%d ", root->data);
}
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue pq;
	QueueInit(&pq);
	if (root)
	{
		QueuePush(&pq, root);
	}
	while (!QueueEmpty(&pq))
	{
		BTNode* front = QueueFront(&pq);
		printf("%d ", front->data);
		QueuePop(&pq);
		if (front->left)
		{
			QueuePush(&pq, front->left);
		}
		if (front->right)
		{
			QueuePush(&pq, front->right);
		}
	}
	printf("\n");
	QueueDestroy(&pq);
}
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue pq;
	QueueInit(&pq);
	if (root)
	{
		QueuePush(&pq, root);
	}
	while (!QueueEmpty(&pq))
	{
		BTNode* front = QueueFront(&pq);
		QueuePop(&pq);
		//遇到空以后跳出后续判断
		if (front == NULL)
		{
			break;
		}
		QueuePush(&pq, front->left);
		QueuePush(&pq, front->right);
	}
	//是空出队列,遇见非空则说明不是完全二叉树
	while (!QueueEmpty(&pq))
	{
		BTNode* front = QueueFront(&pq);
		QueuePop(&pq);
		if (front)
		{
			QueueDestroy(&pq);
			return false;
		}
	}
	QueueDestroy(&pq);
	return true;

}

11.5test.c

#include"BinaryTree.h"
int main()
{
	BTNode* root = CreatBinaryTree();
	// 前序遍历
	BinaryTreePrevOrder(root);
	printf("\n");
	// 中序遍历
	BinaryTreeInOrder(root);
	printf("\n");
	// 后序遍历
	BinaryTreePostOrder(root);
	printf("\n");
	// 判断二叉树是否是完全二叉树
	bool flag = BinaryTreeComplete(root);
	printf("%d\n", flag);
	//层序遍历
	BinaryTreeLevelOrder(root);
	//二叉树查找值为x的节点
	bool flag1 = TreeFind(root, 3);
	BTNode* root1 = BinaryTreeFind(root, 3);
	// 二叉树第k层节点个数
	int KSize = BinaryTreeLevelKSize(root, 3);
	printf("%d\n", KSize);
	// 二叉树叶子节点个数
	int leaf = BinaryTreeLeafSize(root);
	printf("%d\n", leaf);
	 //二叉树节点个数
	int size = BinaryTreeSize(root);
	printf("%d\n", size);
	// 销毁
	BinaryTreePPDestory(&root);
	root = NULL;
}

欢迎各位大佬一起学习交流

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

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

相关文章

mysql主从复制同步、mysql5.7版本安装配置、python操作mysql数据库、mycat读写分离实现

一、mysql主从复制及同步 1、mysql主从自动开机同步 2、配置mysql5.7版本 mysql-5.7.44-linux-glibc2.12-x86_64.tar 启动服务、登录 对数据库进行基本操作 3、使用python操纵mysql数据库 4、编辑python脚本自动化操纵mysql数据库 二、mycat读写分离实现 1.上传jdk和mycat安装包…

项目简介:pyiqa-sal | 图像质量评价代码库

项目地址&#xff1a;https://github.com/Alexkkir/pyiqa-sal/tree/main 这是一个纯python和pytorch编写的图像质量评估工具箱&#xff0c;提供了许多主流全参考&#xff08;FR&#xff09;和无参考&#xff08;NR&#xff09;指标的重新实现&#xff08;如果有的话&#xff0…

MES系统从哪几方面提升企业制造水平?

在当今这个快速变化的制造环境中&#xff0c;企业对于提升制造水平的追求从未停止。制造执行系统&#xff08;MES&#xff09;作为连接企业战略规划与车间实际操作的核心工具&#xff0c;其重要性日益凸显。盘古信息MES系统&#xff0c;凭借其独特的功能模块和创新的设计理念&a…

数据库-DDL语言-数据定义语言

DDL语言-数据定义语言 对数据库对象进行操作的语言, 涉及到的关键字CREATE,ALTER,DROP 对数据库的操作 新建一个数据库 语法 CREATE DATABASE 数据库名 [charset字符集]例 新建一个数据库:mydb CREATE DATABASE mydb;注:SQL语句不区分大小写&#xff0c;但是好的书写习惯…

【考研数学】题目类型:出现两次积分限,但实际上是一次积分。

考研中&#xff0c;有一类题目是出现了两次积分限&#xff08;尤其是人为对题目进行变换、化简时&#xff09;&#xff0c;但解题方法不是利用二重积分方法&#xff0c;而是一次积分。常用凑微分、分部积分法。 以武忠祥老师严选题的两道题目为例&#xff1a; 这两道题就是“披…

模拟实现字符串相关函数(第二十七天)

&#xff01;&#xff01;assert---断言在函数中非常有用&#xff0c;能明确的指出哪里出了错误&#xff0c;然后后续自己方便进行更改 const不能通过直接赋值来改变&#xff0c;但是&#xff01;&#xff01;但是可以通过改地址的方式来改值&#xff01;&#xff01;这时只需要…

如何进军海外短剧市场?从了解海外短剧CPS开始

随着国内土味短剧在各大短视频平台爆火&#xff0c;从初期的蓝海红利到现在的如日中天&#xff0c;其中不乏有人将眼光瞄准了海外市场&#xff0c;预计将在未来几年打造出短剧出海的百亿市场&#xff0c;早期入局海外市场相当于小白一样&#xff0c;而现在和你们分享如何跻身海…

OpenCV图像滤波(15)梯度计算函数Scharr()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 函数使用 Scharr 运算符计算图像的第一个 x- 或 y- 空间导数。 调用 Scharr(src, dst, ddepth, dx, dy, scale, delta, borderType) \texttt{Sc…

数据库(六):事务和索引

一、事务 &#xff08;一&#xff09;概念 1、事务是一组操作集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事物会把所有操作作为一个整体一起向系统提交或者撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失效。 2、默认MySQL的事务是自动…

用关系图和示例解释异步/等待

**解释在各种场景中使用等待时的程序执行流**本文原文 前言 这个文档解释了 Async/Await 是如何工作的。这可能是一个令人困惑的话题。我们将从一些简单的基本概念开始&#xff0c;然后慢慢地向更高级的概念发展。希望这些可视化图表能够帮助那些学习者。 下面的讨论主要是从…

从Retrofit支持suspend协程请求说开去

在现代Android开发中&#xff0c;异步请求已经成为不可或缺的一部分。传统的异步请求往往涉及大量的回调逻辑&#xff0c;使代码难以维护和调试。随着Kotlin协程的引入&#xff0c;异步编程得到了极大的简化。而作为最流行的网络请求库之一&#xff0c;Retrofit早在Kotlin协程的…

【JavaEE】深入探索SpringBoot的日志管理功能与实践应用

目录 SpringBoot 日志日志概述日志使用打印日志在程序中得到⽇志对象使用日志对象打印日志 ⽇志框架介绍(了解)⻔⾯模式(外观模式)SLF4J 框架介绍日志格式的说明⽇志级别日志级别的分类日志级别的使用 ⽇志配置配置⽇志级别⽇志持久化配置⽇志⽂件分割配置⽇志格式 更简单的⽇志…

IBMS管理平台,推动建筑行业向智能化发展

智能建筑管理系统是一套集成了多种技术和功能的综合性管理平台&#xff0c;旨在提高建筑设施的运行效率、减少能源消耗、改善室内环境质量&#xff0c;并为建筑管理者提供全面的监控、控制和分析手段。IBMS管理平台的特点和优势如下&#xff1a; IBMS系统融合了建筑自动化、能源…

2024 国内自闭症学校排名榜:突破边界,创造无限可能

在 2024 年&#xff0c;当家长们面对国内自闭症学校的排名榜时&#xff0c;心中或许充满了期待与困惑。然而&#xff0c;这些排名榜虽然能提供一定的参考&#xff0c;但绝不能成为选择学校的唯一依据。家长们更需要深入了解每所学校的真实情况&#xff0c;通过线下考察&#xf…

网络协议栈应用层的意义(内含思维导图和解析图通俗易懂超易理解)

绪论​&#xff1a; “节省时间的方法就是全力以赴的将所要做的事情完美快速的做完&#xff0c;不留返工重新学习的时间&#xff0c;才能省下时间给其他你认为重要的东西。” 本章主要讲到OSI网络协议栈中的应用层的作用和再次在应用层的角度理解协议的具体意义&#xff0c;以及…

#Datawhale AI夏令营第4期#多模态大模型Task3

写在前面的碎碎念》 为时一个礼拜的学习&#xff0c;即将结束了。回顾这一个礼拜&#xff0c;因此这次的任务较难&#xff0c;大部分的时间都花在跑模型上了&#xff0c;跑一次一天就没了&#xff0c;所以基本没有很好的去尝试优化上分&#xff0c;一个礼拜&#xff0c;差不多…

微商城系统 goods.php SQL注入漏洞复现

0x01 产品简介 微商城系统,又称微信商城系统,是基于微信等社交平台构建的一种小型电子商务系统。该系统融合了社交媒体的互动性和网络商城的交易功能,为商家提供了一个集商品展示、在线交易、营销推广、用户管理、数据分析等功能于一体的综合性电商平台。系统充分利用了微信…

【SecureLock】藏起你的秘密文件!

我们都知道&#xff0c;在 Windows 中可以右键文件夹&#xff0c;选择”属性“&#xff0c;勾选”隐藏“来实现隐藏某个文件夹。 我们还知道&#xff0c;在 Windows 中可以选择勾选 ”显示隐藏的项目和文件夹“&#xff0c;来使上述方法变得形同虚设。 本工具就是用于解决以上…

使用Linux内核自带的V4L2设备驱动 采集图像

一、定义 V4L2代表Video for Linux Two&#xff0c;它是Linux内核的一部分&#xff0c;提供了一种统一的方式来访问各种视频输入/输出设备&#xff0c;如摄像头、电视卡等。 二、工作流程&#xff08;重点&#xff09; 打开设备&#xff0d;> 检查和设置设备属性&#xf…

Elasticsearch-关键词随机查询(8.x)

目录 一、查询语句 二、Java代码实现 基础介绍&#xff1a; ES自定义评分机制:function_score查询详解-阿里云开发者社区ES自定义评分机制:function_score查询详解https://developer.aliyun.com/article/1054571 开发版本详见&#xff1a;Elasticsearch-经纬度查询(8.x-半径…