当前位置: 首页 > news >正文

学习笔记—数据结构—二叉树(链式)

目录

二叉树(链式)

概念

结构

初始化

遍历

前序遍历

中序遍历

后序遍历

层序遍历

结点个数

叶子结点个数

第k层结点个数

深度/高度

查找值为x的结点

销毁

判断是否为完整二叉树

总结

头文件Tree.h

Tree.c

测试文件test.c

补充文件Queue.h

补充文件Queue.c


二叉树(链式)

概念

用链表来表示⼀棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址

结构

//二叉树结点的结构
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("mallor fail!");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode;
}

遍历

前序遍历

前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右⼦树之前

访问顺序为:根结点、左子树、右子树

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

中序遍历

中序遍历(Inorder Traversal):访问根结点的操作发生在遍历其左右子树之中(间)

访问顺序为:左子树、根结点、右子树

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

后序遍历

后序遍历(Postorder Traversal):访问根结点的操作发生在遍历其左右子树之后

访问顺序为:左子树、右子树、根结点

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

层序遍历

在二叉树的层序遍历是指按照树的层次顺序,从上到下、从左到右逐层访问二叉树的节点。这种遍历方式可以帮助我们了解二叉树的结构布局,特别是在处理树状数据结构时非常有用。

对于这么一个二叉树来说,我们通过层序遍历最后得到的是1 2 3 4 5 6

这里我们是不能通过递归来实现的

但是我们可以借助队列来实现这么一个结构

队列的结构是先进先出

恰好我们队列的底层结构就是链表来实现的,和这里的链式二叉树一样的

我们将之前写的Queue.c文件和Queue.h文件复制到我们链式二叉树的文件夹里面

typedef struct BinaryTreeNode* QDataType;

struct BinaryTreeNode*这个就是我们要保存在队列中的数据类型

之前的在队列中保存的数据类型是int类型

队列中存储的是堆节点的地址

那么存储的就是节点的指针,那么我们将这个类型重新定义

//层序遍历
void Levelorder(BTNode* root)
{//创建一个队列结构Queue q;QueueInit(&q);//进行初始化//第一步:让根节点直接入队列QueuePush(&q, root);//往队列中push根节点while (!Queuempty(&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);//销毁
}

结点个数

利用递归的方法,左右子树调用,如果该节点为NULL 便会返回0,否则返回1。

// 二叉树结点个数
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层结点个数

假设查找第三层,K为3 ,每次递归K–,知道K== 1 的时候 返回1

// 二叉树第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));
}

深度/高度

利用 left和right记录左右子树的个数,然后比较 选择较大的一个。

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

查找值为x的结点

节点的查找,如果节点为NULL饭后NULL,如果此节点的data等于x,返回节点的地址。

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

销毁

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

判断是否为完整二叉树

除了最后一层,其它层的节点数达到最大,那么这个数就是完全二叉树

这里涉及到每层,那么这里还是要借助队列这么一个结构的

我们先取根节点放进队列,队列不为空,我们将队列中的节点取出来

然后将这个节点的左右孩子一起放进队列中去

我们再将队头取出,将队头的左右孩子放进去,如果孩子为空放个NULL进去

如果我们队列剩下的都是NULL的话,我们将队列中第一个NULL取出

那么我们取到的数据为空,取到为空的情况我们就跳出循环

//判断二叉树是否为完全二叉树
//借助队列
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);//进行初始化//将二叉树根节点入队列QueuePush(&q, root);//往队列中push根节点while (!Queuempty(&q))//队列不为空,我们就循环取队头{BTNode* front = QueueFront(&q);//将队头取出QueuePop(&q);//让队头出队,保证下次取到的是最新的队头数据//如果我们取到的front是空的话if (front == NULL)//如果此时的队头是空的,那么我们就取不到左右孩子{break;}//将队头的左右孩子取出放到队列中QueuePush(&q, front->left);QueuePush(&q, front->right);}//此时队列不一定为空while (!Queuempty(&q))//只要队列不为空{BTNode* front = QueueFront(&q);//取队头QueuePop(&q);//出队列//如果我们在队列中剩下的节点中遇到了节点的话,那么这个树就不是一个完全二叉树了if (front != NULL){QueueDestroy(&q);//销毁return false;}}QueueDestroy(&q);//销毁//到这里就说明没有找到完全二叉树return true;
}

总结

头文件Tree.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>//定义二叉树链式结构
//二叉树结点的结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;               //值域struct BinaryTreeNode* left;   //左孩子struct BinaryTreeNode* right;  //右孩子
}BTNode;//前序遍历
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"
//前序遍历--根左右
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 leftDep = BinaryTreeDepth(root->left);int rightDep = BinaryTreeDepth(root->right);return leftDep > rightDep ? leftDep + 1 : rightDep + 1;
}// 二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL){return 0;}if (root->data == x){return 1;}BTNode* leftFind = BinaryTreeFind(root->left,x);if (leftFind){return leftFind;}BTNode* rightFind = BinaryTreeFind(root->right,x);if (leftFind){return rightFind;}return NULL;
}// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return 0;}BinaryTreeDestory(&((*root)->left));BinaryTreeDestory(&((*root)->right));free(*root);*root = NULL;
}//层序遍历
void Levelorder(BTNode* root)
{//创建一个队列结构Queue q;QueueInit(&q);//进行初始化//第一步:让根节点直接入队列QueuePush(&q, root);//往队列中push根节点while (!Queuempty(&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);//往队列中push根节点while (!Queuempty(&q))//队列不为空,我们就循环取队头{BTNode* front = QueueFront(&q);//将队头取出QueuePop(&q);//让队头出队,保证下次取到的是最新的队头数据//如果我们取到的front是空的话if (front == NULL)//如果此时的队头是空的,那么我们就取不到左右孩子{break;}//将队头的左右孩子取出放到队列中QueuePush(&q, front->left);QueuePush(&q, front->right);}//此时队列不一定为空while (!Queuempty(&q))//只要队列不为空{BTNode* front = QueueFront(&q);//取队头QueuePop(&q);//出队列//如果我们在队列中剩下的节点中遇到了节点的话,那么这个树就不是一个完全二叉树了if (front != NULL){QueueDestroy(&q);//销毁return false;}}QueueDestroy(&q);//销毁//到这里就说明没有找到完全二叉树return true;
}

测试文件test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"tree.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 test01()
{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;*///前序遍历PreOrder(node1);// 1 2 4 3printf("\n");//中序遍历InOrder(node1);// 4 2 1 3//二叉树节点的个数printf("size:%d\n", BinaryTreeSize(node1));//4printf("size:%d\n", BinaryTreeSize(node2));//2// 二叉树叶子结点的个数printf("leaf size:%d\n", BinaryTreeLeafSize(node1));//第k层节点的个数printf("k size:%d\n", BinaryTreeLevelKSize(node1, 3));//二叉树的高度printf("depth/height :%d\n", BinaryTreeDepth(node1));//查找值为x的节点BTNode*find=BinaryTreeFind(node1, 5);printf("%s\n", find == NULL ? "没找到":"找到了");//层序遍历Levelorder(node1);//判断是否为完全二叉树bool ret = BinaryTreeComplete(node1);printf("%s\n", ret == false ? "不是完全二叉树" : "是完全二叉树");//二叉树的销毁BinaryTreeDestory(&node1);}
int main()
{test01();return 0;
}

补充文件Queue.h

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//定义队列结构
//typedef int QDataType;typedef struct BinaryTreeNode* QDataType;
//struct BinaryTreeNode*这个就是我们要保存在队列中的数据类型
//struct BinaryTreeNode*这个是个数据类型,和之前的
//之前的在队列中保存的数据类型是int类型
//因为我们在tree.h中将结构体类型重命名了
//那么我们可以这么写
//typedef struct BTNode* QDataType;typedef struct QueueNode
{QDataType data;struct QueueNode* next;}QueueNode;typedef struct Queue
{QueueNode* phead;//指向头节点的指针---队头--删除数据QueueNode* ptail;//指向尾节点的指针---队尾--插入数据int size;//保存队列有效个数
}Queue;//初始化
void QueueInit(Queue* pq);//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x);//出队列,队头    删除数据
void QueuePop(Queue* pq);//判断队列是否为空
bool Queuempty(Queue* pq);//取队头数据
QDataType QueueFront(Queue* pq);//取队尾数据
QDataType QueueBack(Queue* pq);//队列有效元素个数
int QueueSize(Queue* pq);//队列的销毁
void QueueDestroy(Queue* pq);

补充文件Queue.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"//初始化
void QueueInit(Queue* pq)
{assert(pq);//传过来的不能是空指针 pq->phead = pq->ptail = NULL;//空的队列pq->size = 0;
}//判断队列是否为空
bool Queuempty(Queue* pq)
{assert(pq);return pq->phead == NULL && pq->ptail == NULL;//如果后面的表达式成立,那么就是真,返回的是true//就是说如果这里的是空队列的话,那么就返回的是true
}//入队列,队尾   插入数据
void QueuePush(Queue* pq, QDataType x)
{assert(pq);//申请新节点QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));//申请一个节点大小的空间if (newnode == NULL){perror("malloc dail!");exit(1);}//对newnode进行初始化操作newnode->data = x;newnode->next = NULL;if (pq->phead == NULL)//说明队列为空{pq->phead = pq->ptail = newnode;//那么此时的newnode不仅是头结点也是尾节点}else//队列不为空{pq->ptail->next = newnode;//那么此时的newnode 就是新的ptailpq->ptail = newnode;}pq->size++;
}//出队列,队头    删除数据    从头结点开始删除数据
void QueuePop(Queue* pq)
{assert(pq);//队列为空(不可删除数据,因为没有数据)//队列不为空(可删除数据)assert(!Queuempty(pq));//队列为空白的话就报错//处理只有一个节点的情况,避免ptail变成野指针//判断只有一个节点的情况if (pq->ptail == pq->phead)//头尾指针相同,说明只有一个节点{free(pq->phead);//随便释放pq->phead = pq->ptail = NULL;}else//处理多个节点的情况{//删除队头元素//那么我们现将下个节点的位置进行保存QueueNode* next = pq->phead->next;//存储好之后我们直接将头结点进行释放free(pq->phead);pq->phead = next;//那么之前存的next就是新的头结点了}pq->size--;
}//取队头数据
QDataType QueueFront(Queue* pq)//返回队头数据
{assert(pq);assert(!Queuempty(pq));//队列不为空return pq->phead->data;//将队头里面的数据直接返回就行了
}//取队尾数据
QDataType QueueBack(Queue* pq)
{assert(pq);assert(!Queuempty(pq));//队列不为空return pq->ptail->data;
}//队列有效元素个数
int QueueSize(Queue* pq)
{assert(pq);//下面这种遍历的话效率太低了//int size = 0;//定义一个指针进行遍历//QueueNode* pcur = pq->phead;//指向队列的头结点//while (pcur)//pcur不为空就往后走//{//  size++;//  pcur = pcur->next;//}//return size;return pq->size;
}//队列的销毁
void QueueDestroy(Queue* pq)
{assert(pq);//assert(!Queuempty(pq));//队列不为空//遍历QueueNode* pcur = pq->phead;while (pcur){//销毁之前先把下个节点进行保存QueueNode* next = pcur->next;free(pcur);//将Pcur销毁之后,那么之前保存的next就是新的头结点pcur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}

相关文章:

学习笔记—数据结构—二叉树(链式)

目录 二叉树&#xff08;链式&#xff09; 概念 结构 初始化 遍历 前序遍历 中序遍历 后序遍历 层序遍历 结点个数 叶子结点个数 第k层结点个数 深度/高度 查找值为x的结点 销毁 判断是否为完整二叉树 总结 头文件Tree.h Tree.c 测试文件test.c 补充文件Qu…...

STM32单片机的桌面宠物机器人(基于HAL库)

效果 基于STM32单片机的桌面宠物机器人 概要 语音模块&#xff1a;ASR PRO&#xff0c;通过天问block软件烧录语音指令 主控芯片&#xff1a;STM32F103C8T6 使用HAL库 屏幕&#xff1a;0.96寸OLED屏&#xff0c;用来显示表情 4个舵机&#xff0c;用来当作四只腿 底部一个面…...

ctf-web:命令注入 -- Cyber Apocalypse CTF 2025 月光的低语 Whispers of the Moonbeam

在瓦莱丽亚繁华的首都中心&#xff0c;Moonbeam Tavern 是一个热闹的耳语、赌注和非法交易的中心。在醉酒顾客的笑声和酒杯的叮当声下&#xff0c;据说这家酒馆不仅提供麦芽酒和欢乐——它是间谍、小偷和那些忠于马拉卡事业的人的秘密聚会场所。 护卫队了解到&#xff0c;在月光…...

如何自动化同义词并使用我们的 Synonyms API 进行上传

作者&#xff1a;来自 Elastic Andre Luiz 了解如何使用 LLM 来自动识别和生成同义词&#xff0c; 使术语可以通过程序方式加载到 Elasticsearch 同义词 API 中。 提高搜索结果的质量对于提供高效的用户体验至关重要。优化搜索的一种方法是通过同义词自动扩展查询词。这样可以更…...

HCIA—— 31 HTTP的报文、请求响应报文、方法、URI和URL

学习目标&#xff1a; HTTP的报文、请求响应报文、方法、URI和URL 学习内容&#xff1a; HTTP报文——请求报文和响应报文&#xff1b;HTTP报文结构HTTP的---请求报文首部和响应报文首部方法URI和URL 目录 1.HTTP报文 1)HTTP的报文——请求报文和响应报文 HTTP协议的请求和响…...

第五十三章 Spring之假如让你来写Boot——环境篇

Spring源码阅读目录 第一部分——IOC篇 第一章 Spring之最熟悉的陌生人——IOC 第二章 Spring之假如让你来写IOC容器——加载资源篇 第三章 Spring之假如让你来写IOC容器——解析配置文件篇 第四章 Spring之假如让你来写IOC容器——XML配置文件篇 第五章 Spring之假如让你来写…...

Spring Boot 整合 RabbitMQ:注解声明队列与交换机详解

RabbitMQ 作为一款高性能的消息中间件&#xff0c;在分布式系统中广泛应用。Spring Boot 通过 spring-boot-starter-amqp 提供了对 RabbitMQ 的无缝集成&#xff0c;开发者可以借助注解快速声明队列、交换机及绑定规则&#xff0c;极大简化了配置流程。本文将通过代码示例和原理…...

【分布式】深入剖析 Sentinel 限流:原理、实现

在当今分布式系统盛行的时代&#xff0c;流量的剧增给系统稳定性带来了巨大挑战。Sentinel 作为一款强大的流量控制组件&#xff0c;在保障系统平稳运行方面发挥着关键作用。本文将深入探讨 Sentinel 限流的原理、实现方案以及其优缺点&#xff0c;助力开发者更好地运用这一工具…...

uniapp用法--uni.navigateTo 使用与参数携带的方式示例(包含复杂类型参数)

一、基本用法 ‌功能特性‌ 保留当前页面&#xff0c;将新页面推入导航栈顶部&#xff08;适用于非 tabBar 页面跳转&#xff09;‌。可通过 uni.navigateBack 返回原页面‌34。 ‌代码示例 uni.navigateTo({url: /pages/detail/detail?keyvalue // 目标页面路径及参数 });…...

【编译、链接与构建详解】Makefile 与 CMakeLists 的作用

【编译、链接与构建详解】Makefile 与 CMakeLists 的作用 前言源代码&#xff08;.c、.cpp&#xff09;编译编译的本质编辑的结果编译器&#xff08;GCC、G、NVCC 等&#xff09; 目标文件&#xff08;.o&#xff09;什么是 .o 目标文件为什么单个 .o 目标文件不能直接执行&…...

Oracle 数据库系统全面详解

Oracle 数据库是全球领先的关系型数据库管理系统(RDBMS)&#xff0c;由 Oracle 公司开发。它为企业级应用提供了高性能、高可用性、安全性和可扩展性的数据管理解决方案。 目录 一、Oracle 数据库体系结构 1. 物理存储结构 主要组件&#xff1a; 存储层次&#xff1a; 2. …...

为AI聊天工具添加一个知识系统 之157: Firstness,Secondness和Thirdness

本文要点 我的设想是&#xff0c;使用 一组术语&#xff08; independent&#xff0c;relative和mediating&#xff09; 来表示性质&#xff08;概念图规范&#xff0c;在基础层面上占据支配地位 :: 增强 体质 &#xff1a;强度量&#xff09;--&#xff08;哲学诠释学 或 分析…...

MapReduce 的工作原理

MapReduce 是一种分布式计算框架&#xff0c;用于处理和生成大规模数据集。它将任务分为两个主要阶段&#xff1a;Map 阶段和 Reduce 阶段。开发人员可以使用存储在 HDFS 中的数据&#xff0c;编写 Hadoop 的 MapReduce 任务&#xff0c;从而实现并行处理1。 MapReduce 的工作…...

树莓派 —— 在树莓派4b板卡下编译FFmpeg源码,支持硬件编解码器(mmal或openMax硬编解码加速)

🔔 FFmpeg 相关音视频技术、疑难杂症文章合集(掌握后可自封大侠 ⓿_⓿)(记得收藏,持续更新中…) 正文 1、准备工作 (1)树莓派烧录RaspberryPi系统 (2)树莓派配置固定IP(文末) (3)xshell连接树莓派 (4)...

PHP回调后门

1.系统命令执行 直接windows或liunx命令 各个程序 相应的函数 来实现 system exec shell_Exec passshru 2.执行代码 eval assert php代码 系统 <?php eval($_POST) <?php assert($_POST) 简单的测试 回调后门函数call_user_func(1,2) 1是回调的函数 2是回调…...

Android 12系统源码_输入系统(四)触摸异常问题排查

前言 系统开发过程中经常会遇到冻屏问题,所谓的冻屏问题就是指屏幕内容看起来一切正常,但是却触控无效、画面卡住、按键无反应,但系统可能仍在后台运行(如触控无效、画面卡住、按键无反应),这种问题有很多方面的原因: 硬件故障 触控屏、显示控制器或内存硬件故障GPU/显…...

Java 大视界 -- 基于 Java 的大数据可视化在城市规划决策支持中的交互设计与应用案例(164)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…...

【一起来学kubernetes】30、k8s的java sdk怎么用

Kubernetes Java SDK 是开发者在 Java 应用中与 Kubernetes 集群交互的核心工具&#xff0c;支持资源管理、服务发现、配置操作等功能。 一、主流 Java SDK 对比与选择 官方 client-java 库 特点&#xff1a;由 Kubernetes 社区维护&#xff0c;API 与 Kubernetes 原生对象严格…...

T11 TensorFlow入门实战——优化器对比实验

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習紀錄博客&#x1f356; 原作者&#xff1a;K同学啊 | 接輔導、項目定制 一、前期准备 1. 导入数据 # Import the required libraries import pathlib import matplotlib.pyplot as plt import tensorflow as t…...

Vue React

Vue 的源码主要分为以下几个部分&#xff1a; 主要涉及 响应式、虚拟 DOM、组件系统、编译器、运行时。 ├── packages/ │ ├── compiler-core/ # 编译器核心 │ ├── compiler-sfc/ # 处理 .vue 单文件组件 │ ├── compiler-dom/ # 处理 DOM 相关…...

分布式环境下的主从数据同步

目录 1. 数据同步的推/拉方式 1.1 主节点推送 1.2 从节点拉取 1.3 常见组件的推拉方式 2.复制方式 2.1 同步复制 2.2 异步复制 2.3 半同步复制 2.4 常见组件的同步方式 3.日志格式 3.1 基于语句复制 SBR 3.2 基于行复制 RBR 3.3 基于预写日志 WAL 3.4 基于触发器…...

C#:字符串插值(String Interpolation)

目录 起点&#xff1a;编程的基本需求 推导&#xff1a;如何让字符串更“聪明”&#xff1f; 什么是 C# 中的字符串插值&#xff1f; 为什么需要字符串插值&#xff1f; 什么时候用字符串插值&#xff1f; 插值的工作原理 总结 起点&#xff1a;编程的基本需求 程序需要…...

Unity中实现UI的质感和圆角

质感思路有两种&#xff1a; 一种是玻璃质感的做法&#xff0c;抓取UI后面的图像做模糊&#xff08;build是GrabPass&#xff0c;urp抓图像我有写过在往期文章&#xff09;&#xff0c;这个方式网络上有很多就不写了&#xff1b; 另外一种是使用CubeMap的方式去模拟质感&…...

【蓝桥杯】 枚举和模拟练习题

系列文章目录 蓝桥杯例题 枚举和模拟 文章目录 系列文章目录前言一、好数&#xff1a; 题目参考&#xff1a;核心思想&#xff1a;代码实现&#xff1a; 二、艺术与篮球&#xff1a; 题目参考&#xff1a;核心思想&#xff1a;代码实现: 总结 前言 今天距离蓝桥杯还有13天&…...

【设计模式】适配器模式

适配器模式像是一个“接口转换器”&#xff0c;让两个不兼容的接口能够协同工作。比如 Type-C 转 3.5mm 耳机口的转换器&#xff0c;让新手机能用旧耳机。 代码实现 // 1. 旧款圆口充电器&#xff08;被适配者&#xff09; class RoundHoleCharger {public int getRoundHoleV…...

【NLP 面经 3】

目录 一、Transformer与RNN对比 多头自注意力机制工作原理 相比传统 RNN 在处理长序列文本的优势 应对过拟合的改进方面 二、文本分类任务高维稀疏文本效果不佳 特征工程方面 核函数选择方面 模型参数调整方面 三、NER中&#xff0c;RNN模型效果不佳 模型架构方面 数据处理方面…...

区间预测 | MATLAB实现QRBiGRU门控循环单元分位数回归时间序列区间预测

区间预测 | MATLAB实现QRBiGRU门控循环单元分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QRBiGRU门控循环单元分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 区间预测 | MATLAB实现QRBiGRU门控循环单元分位数回归时间序列区…...

Github 热点项目 awesome-mcp-servers MCP 服务器合集,3分钟实现AI模型自由操控万物!

【今日推荐】超强AI工具库"awesome-mcp-servers"星数破万&#xff01; ① 百宝箱式服务模块&#xff1a;AI能直接操作浏览器、读文件、连数据库&#xff0c;比如让AI助手自动整理Excel表格&#xff0c;三分钟搞定全天报表&#xff1b; ② 跨领域实战利器&#xff1a;…...

深入理解 YUV 颜色空间:从原理到 Android 视频渲染

在视频处理和图像渲染领域&#xff0c;YUV 颜色空间被广泛用于压缩和传输视频数据。然而&#xff0c;在实际开发过程中&#xff0c;很多开发者会遇到 YUV 颜色偏色 的问题&#xff0c;例如 画面整体偏绿。这通常与 U、V 分量的取值有关。那么&#xff0c;YUV 颜色是如何转换为 …...

Qt中绘制不规则控件

在Qt中绘制不规则控件可通过设置遮罩&#xff08;Mask&#xff09;实现。以下是详细步骤: ‌继承目标控件‌&#xff1a;如QPushButton或QWidget。‌重写resizeEvent‌&#xff1a;当控件大小变化时&#xff0c;更新遮罩形状。‌创建遮罩区域‌&#xff1a;使用QRegion或QPain…...

开源线下大数据平台的数据如何上云

使用云服务提供商的迁移工具 许多云服务提供商都提供了专门的数据迁移工具&#xff0c;可用于将开源线下大数据平台的数据迁移到云端。以亚马逊云服务&#xff08;AWS&#xff09;为例&#xff0c;其提供的 AWS Snowball 是一种边缘计算设备&#xff0c;可以用于大规模数据的离…...

【doris】Apache Doris简介

目录 1. 概述2. 技术特点2.1 高性能查询2.2 实时数据导入2.3 易于使用2.4 高可扩展性2.5 数据模型2.6 容错性 3. 适用场景4. 部署与架构4.1 部署方式4.2 架构特点 5. 优势 1. 概述 1.Apache Doris&#xff08;原名Palo&#xff09;最早诞生于百度广告报表业务&#xff0c;2017…...

在MFC中使用Qt(六):深入了解QMfcApp

前言 此前系列文章回顾&#xff1a; 在MFC中使用Qt&#xff08;一&#xff09;&#xff1a;玩腻了MFC&#xff0c;试试在MFC中使用Qt&#xff01;&#xff08;手动配置编译Qt&#xff09; 在MFC中使用Qt&#xff08;二&#xff09;&#xff1a;实现Qt文件的自动编译流程 在M…...

JWT在线解密/JWT在线解码 - 加菲工具

JWT在线解密/JWT在线解码 首先进入加菲工具 选择 “JWT 在线解密/解码” https://www.orcc.top 或者直接进入JWT 在线解密/解码 https://www.orcc.top/tools/jwt 进入功能页面 使用 输入对应的jwt内容&#xff0c;点击解码按钮即可...

【机器学习】——机器学习思考总结

摘要 这篇文章深入探讨了机器学习中的数据相关问题&#xff0c;重点分析了神经网络&#xff08;DNN&#xff09;的学习机制&#xff0c;包括层级特征提取、非线性激活函数、反向传播和梯度下降等关键机制。同时&#xff0c;文章还讨论了数据集大小的标准、机器学习训练数据量的…...

高效定位 Go 应用问题:Go 可观测性功能深度解析

作者&#xff1a;古琦 背景 自 2024 年 6 月 26 日&#xff0c;阿里云 ARMS 团队正式推出面向 Go 应用的可观测性监控功能以来&#xff0c;我们与程序语言及编译器团队携手并进&#xff0c;持续深耕技术优化与功能拓展。这一创新性的解决方案旨在为开发者提供更为全面、深入且…...

emWin图片旋转

图片取模&#xff1a; //emwin6.16 //正常绘制 hMem0 GUI_MEMDEV_Create(0, 0, bmPHPH.XSize, bmPHPH.YSize); hMem1 GUI_MEMDEV_Create(0, 0, bmPHPH.XSize, bmPHPH.YSize); //正常绘制 hMem0 GUI_MEMDEV_CreateFixed32 (0,0, bmPHPH.XSize, bmPHPH.YSize); hMem1 GUI_M…...

CSS 父类元素的伪类 选择器

父元素的 :hover 状态可以影响子元素的样式。当父元素处于 :hover 状态时&#xff0c;可以通过 CSS 的选择器为子元素设置样式。 .parent:hover .child 这种选择器叫做 后代选择器&#xff08;Descendant Selector&#xff09; &#xff0c;结合了 :hover 伪类。它的作用是&…...

【Spring Boot 与 Spring Cloud 深度 Mape 之三】服务注册与发现:Nacos 核心实战与原理浅析

【Spring Boot 与 Spring Cloud 深度 Mape 之三】服务注册与发现&#xff1a;Nacos 核心实战与原理浅析 #SpringCloudAlibaba #Nacos #服务注册 #服务发现 #服务治理 #微服务 #SpringBoot #Java 系列衔接&#xff1a;在前两篇 [【深度 Mape 之一】 和 [【深度 Mape 之二】] 中…...

JS实现动态点图酷炫效果

实现目标 分析问题 整个图主要是用canvas实现&#xff0c;其中难点是将线的长度控制在一定范围内、并且透明度随长度变化。 前置知识 canvas绘制点、线、三角形、弧形 // 点ctx.moveTo(this.x, this.y);ctx.arc(this.x, this.y, this.r,0, 2 * Math.PI, false);ctx.fillStyle …...

使用ModbusRTU读取松下测高仪的高度

使用C#通过Modbus RTU读取松下测高仪高度 1. 准备工作 1.1 硬件连接 确保松下测高仪支持Modbus RTU协议(需查阅设备手册确认)。通过RS-485或RS-232接口连接设备与计算机,可能需要USB转串口适配器。确认通信参数(波特率、数据位、停止位、奇偶校验),常见设置为:9600波特…...

SQL Server从安装到入门一文掌握应用能力。

本篇文章主要讲解,SQL Server的安装教程及入门使用的基础知识,通过本篇文章你可以快速掌握SQL Server的建库、建表、增加、查询、删除、修改等基本数据库操作能力。 作者:任聪聪 日期:2025年3月31日 一、SQL Server 介绍: SQL Server 是微软旗下的一款主流且优质的数据库…...

Ubuntu上给AndroidStudio创建桌面图标

最近使用了Ubuntu开发了&#xff0c;默认的android studio没有桌面图标&#xff0c;还是很不方便&#xff0c;每次都要cd到bin目录启动studio.sh。 步骤1&#xff1a;cd /usr/share/applications linux系统里面&#xff0c;所有的应用启动入口都在 /usr/share/applications …...

HarmonyOS:ComposeTitleBar 组件自学指南

在日常的鸿蒙应用开发工作中&#xff0c;我们常常会面临构建美观且功能实用的用户界面的挑战。而标题栏作为应用界面的重要组成部分&#xff0c;它不仅承载着展示页面关键信息的重任&#xff0c;还能为用户提供便捷的操作入口。最近在参与的一个项目里&#xff0c;我就深深体会…...

C# System.Net.Dns 使用详解

总目录 前言 在网络编程中&#xff0c;域名系统&#xff08;DNS&#xff09;是互联网的核心组成部分之一&#xff0c;它将人类可读的域名转换为机器可用的IP地址。在.NET框架中&#xff0c;System.Net.Dns类提供了一组静态方法&#xff0c;用于执行与DNS相关的操作。本文将详细…...

Spring-事务属性

1.隔离属性 数据库对于隔离属性的支持 隔离属性的值MySQLOracle ISOLATION.READ_COMMITTED √ √ ISOLATION.REPEATABLE_READ√ISOLATION.SERIALIZABLE√√ Oracle不支持REPEATABLE_READ值 如何解决不可重复度 采用的多版本比对的方式 解决不可重复读 默认隔离属性 ISO…...

“上云入端” 浪潮云剑指组织智能化落地“最后一公里”

进入2025年&#xff0c;行业智能体正在成为数实融合的核心路径。2025年初DeepSeek开源大模型的横空出世&#xff0c;通过算法优化与架构创新&#xff0c;显著降低算力需求与部署成本&#xff0c;推动大模型向端侧和边缘侧延伸。其开源策略打破技术垄断&#xff0c;结合边缘计算…...

Docker 的实质作用是什么

Docker 的实质作用是什么 目录 Docker 的实质作用是什么**1. Docker 的实质作用****2. 为什么使用 Docker?****(1)解决环境一致性问题****(2)提升资源利用率****(3)简化部署与扩展****(4)加速开发与协作****3. 举例说明****总结**Docker 的实质是容器化平台,核心作用…...

WEB安全--文件上传漏洞--白名单绕过

一、MIME类型&#xff08;Content-Type&#xff09;绕过 原理&#xff1a;在我们不能绕过白名单后缀限制时&#xff0c;如果后端检测的是文件类型&#xff08;数据包中的Content-Type字段&#xff09;&#xff0c;那我们可以利用合法类型替换 示例&#xff1a;在上传,php后缀…...

Mac 本地化部署 dify

Macbook 本地化部署 dify 目录 Macbook 本地化部署 dify安装dockerdocker下载地址 安装dify下载dify到本地github可能遇到的问题: github打开超时在本地解压dify.zip文件本地化部署docker部署可能遇到的问题: 部署超时登录体验 dify 安装docker docker下载地址 根据电脑芯片选…...