用C语言实现的——一个支持完整增删查改功能的二叉排序树BST管理系统,通过控制台实现用户与数据结构的交互操作。
一、知识回顾
二叉排序树(Binary Search Tree,BST),又称二叉查找树或二叉搜索树,是一种特殊的二叉树数据结构。
基本性质:
①有序性
对于树中的每个节点,其左子树中所有节点的值都小于该节点的值。
其右子树中所有节点的值都大于该节点的值。
②子树递归性
左子树和右子树也都是二叉排序树。
基本操作的时间复杂度
优点:
高效性:在平衡情况下,查找、插入和删除操作的时间复杂度均为 O(logn),效率较高。
动态性:支持动态插入和删除操作,便于数据的增删改查。
缺点:
最坏情况退化:如果插入的数据是有序的,可能导致树退化为链表,此时时间复杂度变为 O(n)。
额外内存开销:每个节点需要存储左右子节点的指针,增加了内存开销。
应用场景:
动态查找表:适用于需要频繁插入、删除和查找的数据集合。
排序算法:通过中序遍历可以得到一个有序序列。
文件系统:用于文件的快速检索和管理。
二叉排序树的结构和操作使其在需要高效查找和动态更新的场景中具有广泛的应用价值。
二、代码分析
1.二叉树节点结构体定义Node
typedef struct Node 创建了一个新的数据类型 Node,用于表示二叉树中的节点。
int data:用于存储节点的数据或值。
struct Node* left:一个指向该节点左孩子节点的指针。
struct Node* right:一个指向该节点右孩子节点的指针。
2. 创建二叉树节点createNode
函数createNode:
用于创建一个新的二叉树节点。函数接收一个整型参数data,表示节点要存储的数据。
作用:是分配内存、初始化节点并返回节点的指针。
① 使用malloc为新的Node结构体分配内存。如果分配成功,返回一个指向该内存的指针转换为
Node*类型。
② 检查newNode是否为NULL,如果是NULL,说明内存分配失败,打印错误信息并返回NULL。
③ 如果内存分配成功,将data赋值给newNode->data。
④ 将左子节点指针newNode->left和右子节点指针newNode->right初始化为NULL,表明新节点初
始时没有左右子节点。
⑤ 最后返回创建好的新节点指针。
3. 插入操作insert
函数作用:
该函数用于将一个新的数据值插入到二叉排序树中,
同时保持二叉排序树的性质:
对于树中的每个节点,其左子树中所有节点的值都小于该节点的值。
其右子树中所有节点的值都大于该节点的值。
参数说明:
Node* root:指向当前树的根节点的指针。如果树为空,root 为 NULL。
int data:要插入的新数据值。
如果 root 为 NULL,说明当前树为空,因此直接创建一个新节点并返回它作为根节点。这是通过调用 createNode(data) 实现的。
如果 data 小于 root->data,则递归地将数据插入到 root 的左子树中。
如果 data 大于 root->data,则递归地将数据插入到 root 的右子树中。
这样可以确保在插入过程中保持二叉排序树的性质。
最后,函数返回当前树的根节点,以便在递归调用中更新父节点的左或右子节点。
4.查找最小值节点的函数 findMin
通过一个 while 循环持续向左遍历树。只要当前节点的左子节点不为空,就将当前节点更新为它的左子节点。
当循环结束时,当前节点就是树中最左的节点,也就是值最小的节点,直接返回该节点。
二叉排序树中的最小值节点一定是最左的节点,因为每次向左移动都会找到更小的值。所以,通过从根节点开始,不断向左子节点遍历,直到左子节点为 NULL 为止,此时当前节点就是整个树的最小值节点。
5.删除函数delete
删除操作需要处理以下三种情况:
①要删除的节点不存在于树中:直接返回原树。
②要删除的节点存在:
a. 节点没有子节点(叶子节点):直接删除该节点。
b. 节点有一个子节点:用其子节点替换该节点。
c. 节点有两个子节点:用其右子树的最小值节点替换该节点,并递归删除右子树中的这个最小值节点。
参数说明:
Node* root:指向当前树的根节点的指针。
int data:要删除的节点的数据值。
1. 查找要删除的节点:
如果 root 为 NULL,说明树中没有要删除的节点,直接返回 NULL。
如果 data 小于 root->data,递归地在左子树中查找并删除。
如果 data 大于 root->data,递归地在右子树中查找并删除。
2.节点找到后的处理:
情况1:节点没有左子节点:
将右子节点存储在临时变量 temp 中。
释放当前节点的内存。
返回 temp 作为新的子树根节点。
情况2:节点没有右子节点:
将左子节点存储在临时变量 temp 中。
释放当前节点的内存。
返回 temp 作为新的子树根节点。
情况3:节点有两个子节点:
找到右子树中的最小值节点(findMin(root->right))。
将当前节点的数据替换为这个最小值。
递归地删除右子树中的这个最小值节点。
最后返回当前树的根节点,以便在递归调用中更新父节点的左或右子节点。
6. 搜索操作search
终止条件:
如果当前节点为空(root == NULL),说明查找路径已到达树的尽头,未找到目标值,返回 NULL如果当前节点的值等于目标值(root->data == data),返回当前节点指针。
递归查找:
如果目标值小于当前节点值,递归在左子树中查找。
否则,递归在右子树中查找。
7.先序遍历preOrder
根节点 → 左子树 → 右子树”的顺序访问节点
空树判断:函数首先检查传入的根节点是否为空(if (root != NULL))。如果根节点为空,说明树为空或已遍历到叶子节点的子节点,此时直接返回,不再进行后续操作。
访问根节点:如果根节点不为空,先打印当前根节点的数据(printf("%d ", root->data))。
递归遍历左子树:然后递归调用 preOrder 函数,传入根节点的左子节点(preOrder(root->left)),对左子树进行先序遍历。
递归遍历右子树:最后递归调用 preOrder 函数,传入根节点的右子节点(preOrder(root->right)),对右子树进行先序遍历。
8.中序遍历inOeder
中序遍历的顺序是“左子树 → 根节点 → 右子树”,在二叉排序树中,这种遍历方式可以按升序输出所有节点的值。
空树判断:函数先检查传入的根节点是否为空(if (root != NULL))。如果为空,直接返回,结束当前递归调用。
递归左子树:如果根节点不为空,先递归调用 inOrder 遍历左子树(inOrder(root->left))。
访问根节点:遍历完左子树后,打印当前根节点的值(printf("%d ", root->data))。
递归右子树:最后递归调用 inOrder 遍历右子树(inOrder(root->right))。
9.后续遍历posOeder
后序遍历的顺序是“左子树 → 右子树 → 根节点”,常用于确保在处理父节点之前先处理所有的子节点。
空树判断:函数先检查传入的根节点是否为 NULL(if (root != NULL))。如果为空,直接返回,结束当前递归调用。
递归左子树:如果根节点不为空,先递归调用 postOrder 遍历左子树(postOrder(root->left))。
递归右子树:然后递归调用 postOrder 遍历右子树(postOrder(root->right))。
访问根节点:最后打印当前根节点的值(printf("%d ", root->data))。
10.二叉树的层次遍历levelOrder
空树判断:函数开始时检查根节点是否为 NULL,如果是空树则直接返回。
队列初始化:使用一个数组 queue 作为队列来辅助遍历。队列的前端和后端分别由 front 和 rear 索引表示。
根节点入队:
queue[rear++] = root;
将根节点添加到队列中。rear++ 表示先将根节点存入队列位置 rear,然后 rear 自增1。
这一步将根节点作为层次遍历的起始点。
遍历循环:当队列不为空时,持续执行以下操作:
Node* current = queue[front++];
从队列的前端取出一个节点,赋值给指针变量 current。
front++ 表示先取出位置 front 的节点,然后 front 自增1,指向下一个待处理的节点。
节点出队:从队列前端取出一个节点(current),并打印其数据。
子节点入队:如果当前节点有左子节点,则将左子节点添加到队列的末尾。同样地,如果有右子节点,也将其添加到队列末尾。
if (current->left != NULL)
检查当前节点是否有左子节点。如果左子节点不为空,则执行下列代码。
queue[rear++] = current->left;
将当前节点的左子节点添加到队列的末尾。
rear++ 表示先存入左子节点,然后 rear 自增1。
if (current->right != NULL)
检查当前节点是否有右子节点。如果右子节点不为空,则执行下列代码。
queue[rear++] = current->right;
将当前节点的右子节点添加到队列的末尾。
rear++ 表示先存入右子节点,然后 rear 自增1。
循环终止:当队列为空时,树的所有节点都已被访问,遍历完成。
优点:
广度优先顺序:按照从左到右、从上到下的顺序访问节点,这在某些应用场景(如查找最短路径)中非常有用。
非递归实现:使用队列实现,避免了递归可能带来的栈溢出问题。
缺点与限制:
内存占用:需要额外的队列空间来存储待访问的节点,这可能导致更高的内存使用。
实现复杂性:相较于递归实现的先序、中序、后序遍历,层次遍历的代码相对复杂,需要管理队列的前端和后端。
11.释放空间函数
①:void freeTree(Node* root)
定义了一个名为 freeTree 的函数,用于释放以 root 为根节点的二叉树所占用的内存。
②:if (root == NULL) return;
检查当前节点是否为空。如果节点为空,直接返回,因为没有内存需要释放。
这是递归函数的终止条件,防止对空指针进行操作。
③:freeTree(root->left);
递归调用 freeTree 函数,释放当前节点的左子树所占用的内存。
这一步确保在释放当前节点之前,其左子树的所有节点都被释放。
④:freeTree(root->right);
递归调用 freeTree 函数,释放当前节点的右子树所占用的内存。
这一步确保在释放当前节点之前,其右子树的所有节点都被释放。
⑤:free(root);
使用 free 函数释放当前节点所占用的内存。
这是实际释放内存的操作,必须在左右子树都被释放之后执行,以确保所有子节点的内存都已被正确释放。
12.循环输入部分
实现了二叉排序树的初始化阶段,允许用户批量插入节点,直到用户输入特定值(-1)为止。
第1-2行:提示信息
第3-4行:输入循环
第5-6行:提示输入数值
提示用户输入一个整数值。
使用 scanf 函数读取用户输入的整数值,并将结果存储在 data 变量中,返回值存储在 scanResult 中,用于检查输入是否有效。
第7-12行:处理无效输入
如果 scanf 返回值不是1,说明输入不是有效的整数。
使用 getchar() 清空输入缓冲区,直到遇到换行符 \n。
提示用户输入错误,并使用 continue 跳过本次循环的剩余部分,重新开始循环。
第22行:插入节点
调用 insert 函数,将用户输入的 data 插入到二叉排序树中。
更新 root 指针,以反映树结构的变化。
第24-25行:清理输入缓冲区
在退出循环后,再次清空输入缓冲区,确保后续输入操作不会受到之前输入的影响。
12. 调试演示:
=== 二叉排序树初始化 ===
请输入要插入的数值(输入-1结束):
输入数值: 50
输入数值: 30
输入数值: 70
输入数值: 20
输入数值: 40
输入数值: -1
初始化完成,进入操作菜单...
二叉排序树操作菜单:
1. 插入节点
2. 删除节点
...(后续操作正常)
三、完整代码
#include <stdio.h>
#include <stdlib.h>typedef struct Node
{int data;struct Node* left;struct Node* right;
} Node;Node* createNode(int data)
{Node* newNode = (Node*)malloc(sizeof(Node));if (newNode == NULL) {printf("内存分配错误\n");return NULL;}newNode->data = data;newNode->left = newNode->right = NULL;return newNode;
}Node* insert(Node* root, int data)
{if (root == NULL){return createNode(data);}if (data < root->data){root->left = insert(root->left, data);}else if (data > root->data) {root->right = insert(root->right, data);}return root;
}Node* findMin(Node* root)
{while (root->left != NULL) {root = root->left;}return root;
}Node* delete(Node* root, int data)
{if (root == NULL) return root;if (data < root->data){root->left = delete(root->left, data);}else if (data > root->data) {root->right = delete(root->right, data);}else{// 节点找到if (root->left == NULL) {Node* temp = root->right;free(root);return temp;}else if (root->right == NULL) {Node* temp = root->left;free(root);return temp;}// 有两个子节点的情况Node* temp = findMin(root->right);root->data = temp->data;root->right = delete(root->right, temp->data);}return root;
}Node* search(Node* root, int data)
{if (root == NULL || root->data == data) {return root;}if (data < root->data) {return search(root->left, data);}return search(root->right, data);
}void preOrder(Node* root)
{if (root != NULL){printf("%d ", root->data);preOrder(root->left);preOrder(root->right);}
}void inOrder(Node* root)
{if (root != NULL) {inOrder(root->left);printf("%d ", root->data);inOrder(root->right);}
}void postOrder(Node* root)
{if (root != NULL){postOrder(root->left);postOrder(root->right);printf("%d ", root->data);}
}void levelOrder(Node* root)
{if (root == NULL) return;Node* queue[100];int front = 0, rear = 0;queue[rear++] = root;while (front < rear){Node* current = queue[front++];printf("%d ", current->data);if (current->left != NULL){queue[rear++] = current->left;}if (current->right != NULL) {queue[rear++] = current->right;}}
}void freeTree(Node* root)
{if (root == NULL)return;freeTree(root->left);freeTree(root->right);free(root);
}void displayMenu()
{printf("\n\n二叉排序树操作菜单:");printf("\n1. 插入节点");printf("\n2. 删除节点");printf("\n3. 查找节点");printf("\n4. 前序遍历");printf("\n5. 中序遍历");printf("\n6. 后序遍历");printf("\n7. 层次遍历");printf("\n8. 退出系统");printf("\n请输入您的选择:");
}int main()
{Node* root = NULL;int choice, data;// 初始批量插入阶段printf("=== 二叉排序树初始化 ===\n");printf("请输入要插入的数值(输入-1结束):\n");while (1){printf("输入数值: ");int scanResult = scanf("%d", &data);// 处理无效输入if (scanResult != 1) {while (getchar() != '\n'); // 清空输入缓冲区printf("输入错误,请重新输入!\n");continue;}// 结束条件判断if (data == -1) {printf("初始化完成,进入操作菜单...\n\n");break;}root = insert(root, data);}// 清理输入缓冲区while (getchar() != '\n');while (1) {displayMenu();scanf_s("%d", &choice);switch (choice){case 1:printf("请输入要插入的数值:");scanf_s("%d", &data);root = insert(root, data);break;case 2:printf("请输入要删除的数值:");scanf_s("%d", &data);if (search(root, data) == NULL) {printf("数值 %d 不存在于树中\n", data);}else {root = delete(root, data);printf("数值 %d 已成功删除\n", data);}break;case 3:printf("请输入要查找的数值:");scanf_s("%d", &data);if (search(root, data) != NULL){printf("数值 %d 存在于树中\n", data);}else {printf("数值 %d 不存在于树中\n", data);}break;case 4:printf("前序遍历结果:");preOrder(root);break;case 5:printf("中序遍历结果:");inOrder(root);break;case 6:printf("后序遍历结果:");postOrder(root);break;case 7:printf("层次遍历结果:");levelOrder(root);break;case 8:printf("正在退出程序...\n");freeTree(root); // 释放内存exit(0);default:printf("无效选项,请重新输入!\n");}}return 0;
}
该程序实现了以下功能:
1.交互式二叉排序树管理
支持通过控制台进行动态操作,提供清晰的中文菜单界面
2.初始化批量建树
启动时支持连续输入多个数值构建初始树结构,输入 -1 结束初始化
3.核心操作功能
插入新节点
删除指定数值节点
查找数值是否存在
四种遍历方式:前序、中序、后序、层次遍历
4.内存管理
退出时自动释放整棵树内存
包含输入错误处理机制
5.数据展示
实时显示操作结果(成功/失败提示)
每次遍历操作后立即输出遍历序列
程序本质是一个支持完整增删查改功能的二叉排序树管理系统,通过控制台实现用户与数据结构的交互操作。
相关文章:
用C语言实现的——一个支持完整增删查改功能的二叉排序树BST管理系统,通过控制台实现用户与数据结构的交互操作。
一、知识回顾 二叉排序树(Binary Search Tree,BST),又称二叉查找树或二叉搜索树,是一种特殊的二叉树数据结构。 基本性质: ①有序性 对于树中的每个节点,其左子树中所有节点的值都小于该节点的…...
uniapp-商城-53-后台 商家信息(更新修改和深浅copy)
1、概述 文章主要讨论了在数据库管理中如何处理用户上传和修改商家信息的问题,特别是通过深浅拷贝技术来确保数据更新的准确性和安全性。 首先,解释了深拷贝和浅拷贝的区别:浅拷贝使得两个变量共享相同的内存地址,而深拷贝则创建新…...
vue数据可视化开发echarts等组件、插件的使用及建议-浅看一下就行
在 Vue 项目中使用 ECharts 进行数据可视化开发时,可以结合 Vue 的响应式特性和 ECharts 的强大功能,实现动态、交互式的图表展示。 一、ECharts 基础使用 1. 安装 ECharts npm install echarts2. 在 Vue 组件中使用 ECharts <template><div…...
百度AI战略解析:文心一言与自动驾驶的双轮驱动
百度AI战略解析:文心一言与自动驾驶的双轮驱动 系统化学习人工智能网站(收藏):https://www.captainbed.cn/flu 文章目录 百度AI战略解析:文心一言与自动驾驶的双轮驱动摘要引言一、技术架构:大模型与自动…...
MCP Streamable HTTP 传输层的深度解析及实战分析
一、Streamable HTTP 传输层设计革新 1. 核心设计思想 协议融合:将 HTTP/1.1、HTTP/2 与 SSE 协议特性深度整合动态协商:通过 HTTP Header 实现传输协议动态协商(X-MCP-Transport)流式优先:默认启用流式传输,支持半双工通信背压控制:基于 HTTP/2 流级流量控制实现智能速…...
六大设计模式--OCP(开闭原则):构建可扩展软件的基石
写在前面:一个真实的项目悲剧 某电商平台促销功能每次迭代都需要修改核心订单类,导致: ✅ 双十一活动修改导致支付功能崩溃 ✅ 新人优惠引发会员系统连环故障 ✅ 每次发布需全量回归测试 根本原因:系统架构违反开闭原则 一、开闭…...
ActiveMQ 生产环境问题排查与调优指南(一)
一、引言 在当今复杂的分布式系统架构中,消息中间件扮演着至关重要的角色,而 ActiveMQ 作为一款广泛使用的开源消息中间件,凭借其丰富的特性、良好的稳定性和易用性,在众多企业的生产环境中占据了一席之地。它基于 JMS(…...
深入理解 JavaScript 中的 FileReader API:从理论到实践
文章目录 深入理解 JavaScript 中的 FileReader API:从理论到实践前言什么是 FileReader?核心特性 FileReader 的常用方法事件监听实际案例案例 1:读取文本文件内容案例 2:图片预览(Data URL)案例 3&#x…...
Google LLM prompt engineering(谷歌提示词工程指南)
文章目录 基本概念AI输出配置:调整AI的回答方式输出长度温度(Temperature)Top-K和Top-P 提示技术:让AI更好地理解你零样本提示(Zero-shot)少样本提示(Few-shot)系统提示(…...
前端npm包发布流程:从准备到上线的完整指南
无论是使用第三方库还是创建和分享自己的工具,npm都为我们提供了一个强大而便捷的平台,然而很多开发者在将自己的代码发布到npm上时往往面临各种困惑和挑战,本篇文章将从准备工作到发布上线,探讨如何让npm包更易发布及避免常见的坑…...
【MySQL】表空间结构 - 从何为表空间到段页详解
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
OB Cloud 云数据库V4.3:SQL +AI全新体验
OB Cloud 云数据库V4.3:SQL AI全新体验 简介 OB Cloud云数据库全新升级至V4.3版本,为用户带来了SQLAI的最新技术体验,强化数据库的传统功能,深度融合了人工智能技术,引入先进的向量检索功能和优化的SQL引擎,…...
【Linux系统】第四节—详解yum+vim
hello 我是云边有个稻草人 Linux—本节课所属专栏—欢迎订阅—持续更新中~ 目录 画板—本节课知识点详解 一、软件包管理器 1.1 什么是软件包 1.2 Linux软件⽣态 1.3 yum具体操作 【查看软件包】 【安装软件】 【卸载软件】 【注意事项】 1.4 安装源 二、vim 2.1 …...
Git的核心作用详解
一、版本控制与历史追溯 Git作为分布式版本控制系统,其核心作用是记录代码的每一次修改,形成完整的历史记录。通过快照机制,Git会保存每次提交时所有文件的完整状态(而非仅记录差异),确保开发者可以随时回…...
Three.js + React 实战系列 - 职业经历区实现解析 Experience 组件✨(互动动作 + 3D 角色 + 点击切换动画)
对个人主页设计和实现感兴趣的朋友可以订阅我的专栏哦!!谢谢大家!!! 在这篇博客中,我们将分析一个极其有趣和互动性的组件 - Experience.jsx,该组件用于在主页中呈现个人的工作经历。 这个组件…...
3D虚拟工厂vue3+three.js
1、在线体验 3D虚拟工厂在线体验 2、功能介绍 1. 全屏显示功能2. 镜头重置功能3. 企业概况信息模块4. 标签隐藏/显示功能5. 模型自动旋转功能6. 办公楼分层分解展示7. 白天/夜晚 切换8. 场景资源预加载功能9. 晴天/雨天/雾天10. 无人机视角模式11. 行人漫游视角模式12. 键盘…...
[Java实战]Spring Boot 解决跨域问题(十四)
[Java实战]Spring Boot 解决跨域问题(十四) 一、CORS 问题背景 什么是跨域问题? 当浏览器通过 JavaScript 发起跨域请求(不同协议、域名、端口)时,会触发同源策略限制,导致请求被拦截。 示例场…...
嵌入式硬件篇---CAN
文章目录 前言1. CAN协议基础1.1 物理层特性差分信号线终端电阻通信速率总线拓扑 1.2 帧类型1.3 数据帧格式 2. STM32F103RCT6的CAN硬件配置2.1 硬件连接2.2 CubeMX配置启用CAN1模式波特率引脚分配过滤器配置(可选) 3. HAL库代码实现3.1 CAN初始化3.2 发…...
(2025)图文解锁RAG从原理到代码实操,代码保证可运行
什么是RAG RAG(检索增强生成)是一种将语言模型与可搜索知识库结合的方法,主要包含以下关键步骤: 数据预处理 加载:从不同格式(PDF、Markdown等)中提取文本分块:将长文本分割成短序列(通常100-500个标记),作为检索单元…...
TWAS、GWAS、FUSION
全基因组关联研究(GWAS,Genome-Wide Association Study)是一种统计学方法,用于在全基因组水平上识别与特定性状或疾病相关的遗传变异。虽然GWAS可以识别与性状相关的遗传信号,但它并不直接揭示这些遗传变异如何影响生物…...
大模型微调终极方案:LoRA、QLoRA原理详解与LLaMA-Factory、Xtuner实战对比
文章目录 一、微调概述1.1 微调步骤1.2 微调场景 二、微调方法2.1 三种方法2.2 方法对比2.3 关键结论 三、微调技术3.1 微调依据3.2 LoRA3.2.1 原理3.2.2 示例 3.3 QLoRA3.4 适用场景 四、微调框架4.1 LLaMA-Factory4.2 Xtuner4.3 对比 一、微调概述 微调(Fine-tun…...
FHE 之 面向小白的引导(Bootstrapping)
1. 引言 FHE初学者和工程师常会讨论的一个问题是; “什么是引导(bootstrapping)?” 从理论角度看,这个问题的答案很简单: 引导就是套用 Gentry 提出的思想——在加密状态下同态地执行解密操作ÿ…...
安装:Kali2025+Docker
安装:Kali2025Docker Kali2025安装 直接官网下载WMware版本 https://www.kali.org/get-kali/#kali-virtual-machines 直接打开运行 初始用户密码 kali/kali sudo -i 命令切换到root 更换镜像 切换到其他可用的 Kali Linux 镜像源可能会解决问题,可以使用国内的镜像源&…...
什么是深拷贝什么是浅拷贝,两者区别
什么是深拷贝什么是浅拷贝,两者区别 1.深拷贝 递归复制对象的所有层级,嵌套的引用类型属性,最后生成一个完全独立的新对象,与原对象无任何引用关联。 特点: 新对象和原对象的所有层级属性是独立的(修改…...
A2A大模型协议及Java示例
A2A大模型协议概述 1. 协议作用 A2A协议旨在解决以下问题: 数据交换:不同应用程序之间的数据格式可能不一致,A2A协议通过定义统一的接口和数据格式解决这一问题。模型调用:提供标准化的接口,使得外部应用可以轻松调…...
第七章 数据库编程
1 数据库编程基础 1.1 数据库系统概述 数据库系统是由数据库、数据库管理系统(DBMS)和应用程序组成的完整系统。其主要目的是高效地存储、管理和检索数据。现代数据库系统通常分为以下几类: 关系型数据库(RDBMS):如MySQL、PostgreSQL、Oracle等&#x…...
电影感户外哑光人像自拍摄影Lr调色预设,手机滤镜PS+Lightroom预设下载!
调色详情 电影感户外哑光人像自拍摄影 Lr 调色,是借助 Lightroom 软件,针对户外环境下拍摄的人像自拍进行后期处理。旨在模拟电影画面的氛围与质感,通过调色赋予照片独特的艺术气息。强调打造哑光效果,使画面色彩不过于浓烈刺眼&a…...
C++--类的构造函数与初始化列表差异
一,引言 在类中成员函数的构造函数担任其将对象初始化的作用,而初始化列表也有着相似的作用。大部分人建议都是初始化列表进行初始化,本文主要进行讲解二者的区别。 首先看一下构造函数的初始化方式: #define _CRT_SECURE_NO…...
深入浅出之STL源码分析4_类模版
1.引言 我在上面的文章中讲解了vector的基本操作,然后提出了几个问题。 STL之vector基本操作-CSDN博客 1.刚才我提到了我的编译器版本是g 11.4.0,而我们要讲解的是STL(标准模板库),那么二者之间的关系是什么&#x…...
Lambda表达式解读
本文通过具体案例演示函数式接口Function<T,R>的三种实现方式演变过程。 一、传统匿名内部类实现 Integer resInt1 t1(new Function<String, Integer>() {Overridepublic Integer apply(String s) {int i Integer.parseInt(s);return i;} });实现特点࿱…...
PySide6 GUI 学习笔记——常用类及控件使用方法(常用类边距QMarginsF)
文章目录 类简介方法总览关键说明示例代码 类简介 QMarginsF 用于定义四个浮点型边距(左、上、右、下),描述围绕矩形的边框尺寸。所有边距接近零时 isNull() 返回 True,支持运算符重载和数学运算。 方法总览 方法名/运算符参数返…...
Android方法耗时监控插件开发
需求:自定义一个Gradle插件,这个Gradle插件可以统计方法的耗时,并当方法耗时超过阈值时,可以通过打印Log日志在控制台,然后可以通过Log定位到耗时方法的位置,帮助我们找出耗时方法和当前线程名,…...
TWAS / FUSION
FUSION 是一套用于执行转录组范围和调控组范围关联研究(TWAS 和 RWAS)的工具。它通过构建功能/分子表型的遗传成分的预测模型,并使用 GWAS 汇总统计数据预测和测试该成分与疾病的关联,目标是识别 GWAS 表型与仅在参考数据中测量的…...
C++中的static_cast:类型转换的安全卫士
C中的static_cast:类型转换的安全卫士 在C编程中,类型转换是不可避免的操作,而static_cast作为C四大强制类型转换运算符之一,是最常用且相对安全的一种转换方式。今天我们就来深入探讨一下这个重要的类型转换工具。 一、static_…...
uniapp-商城-51-后台 商家信息(logo处理)
前面对页面基本进行了梳理和说明,特别是对验证规则进行了阐述,并对自定义规则的兼容性进行了特别补充,应该说是干货满满。不知道有没有小伙伴已经消化了。 下面我们继续前进,说说页面上的logo上传组件,主要就是uni-fil…...
04 mysql 修改端口和重置root密码
当我们过了一段时间,忘了自己当初创建的数据库密码和端口,或者端口被占用了,要怎么处理呢 首先,我们先停止mysql。 一、修改端口 打开my.ini文件,搜索port,默认是3306,根据你的需要修改为其他…...
多线程 2 - 死锁问题
死锁 死锁,是多线程代码中的一类经典问题。加锁能够解决线程安全问题,但如果加锁方式不当,就很可能产生死锁。 出现死锁的三种场景 1、一个线程一把锁 就像上篇文章讲过的,如果对同一个线程上了两把锁,而且上的锁是…...
网络原理(Java)
注:此博文为本人学习过程中的笔记 在网络初始中谈到TCP/IP五层模型,接下来我们将介绍这里面涉及到的网络协议。 应用层是程序员接触最多的层次,程序员写的代码只要涉及到网络通信都可以视为是应用层的一部分。应用层里的东西和程序员直接相…...
HDFS 常用基础命令详解——快速上手分布式文件系统
简介: 本文面向刚接触 Hadoop HDFS(Hadoop 分布式文件系统)的读者,结合 CSDN 博客风格,系统梳理最常用的 HDFS 客户端命令,并配以示例和注意事项,帮助你在开发和运维中快速掌握 HDFS 的文件管理…...
Unity Shaders and Effets Cookbook
目录 作者简介 审稿人简介 前言 我是偏偏 Unity Shaders and Effets Cookbook 第一章:Diffuse Shading - 漫反射着色器 第二章:Using Textures for Effects - 着色器纹理特效的应用 第三章:Making Your Game Shine with Specular - 镜…...
Markdown—LaTeX 数学公式
目录 一、字母1. 希腊大写字母2. 希腊小写字母3. 花体字母 二、上标和下标1. 上标2. 下标3. 其他 三、括号四、数学符号1. 基本数学符号1)运算符2)常见函数3)分式、根号、累加/乘4)极限5)积分 2. 三角函数与几何符号1&…...
AI 驱动的开发工具
🔧 主流 AI 前端开发工具 1. GitHub Copilot 由 GitHub 与 OpenAI 联合开发,集成在 Visual Studio Code、JetBrains 等主流 IDE 中,提供智能代码补全、函数生成等功能,极大地提高了开发效率。 (CSDN博客) 2. Cursor 一款 AI 驱…...
【入门】数字走向I
描述 输入整数N,输出相应方阵。 输入描述 一个整数N。( 0 < n < 10 ) 输出描述 一个方阵,每个数字的场宽为3。 #include <bits/stdc.h> using namespace std; int main() {int n;cin>>n;for(int i1;i<n*n;i){cout…...
Kubernetes生产实战(十三):灰度发布与蓝绿发布实战指南
在微服务架构中,如何安全高效地发布新版本是每个团队必须掌握的技能。本文将深入讲解Kubernetes中两种主流发布策略的落地实践,附带生产环境真实案例。 一、金丝雀发布(灰度发布):渐进式验证新版本 核心思想…...
数孪实战笔记(1)数字孪生的含义、应用及技术体系
一、含义 数字孪生(Digital Twin)是一种通过数字化模型在虚拟世界中实时映射和模拟物理实体、系统或过程的技术。它的核心目的是通过对现实对象的建模、感知、分析和预测,实现对物理世界的全面感知、智能控制和优化决策。数字孪生 实体对象 …...
深入浅出之STL源码分析5_类模版实例化与特化
在 C 中,类模板的实例化(Instantiation)和特化(Specialization) 是模板编程的核心概念,而 显式实例化(Explicit Instantiation)和隐式实例化(Implicit Insta…...
JDBC演进之路:从基础操作到高效连接池
文章目录 一、JDBC 1.0:手动管理的起点1.1 核心特点1.2 代码示例:1.3 痛点分析 二、JDBC 2.0:配置化的升级2.1 核心改进2.2 代码示例2.3 优势与不足 三、JDBC 3.0:连接池的革命3.1 核心改进3.2 代码示例3.3 核心优势 四、版本对比…...
远程调试---在电脑上devtools调试运行在手机上的应用
1、启动项目–以vite项目为例:先ipconfig查看ip地址 ,然后在vite中配置host为ip地址 2、手机上查看项目:保证手机和电脑在同一局域网, 在手机浏览器打开我们vite启动的项目地址, 3、使用chii进行远程调试 (1) 安装 npm install chii -g (2)启动 chii start -p 8080 (3)在…...
街景主观感知全流程(自建数据集+两两对比程序+Trueskill计算评分代码+训练模型+大规模预测)27
目录 0、Emeditor软件1、Place Pluse 2.0数据集2、街景主观感知大框架2.1 街景主观感知:自建数据集2.2 街景主观感知:两两对比程序2.3 街景主观感知:Trueskill评分2.4 街景主观感知:训练模型,Resnet或EfficientNet或V…...
进阶二:基于HC-SR04和LCD1602的超声波测距
一、实验目的 掌握HC-SR04超声波测距模块的工作原理和使用方法。学会使用LCD1602液晶显示屏显示测量数据。熟悉89C51单片机与外设的接口电路设计和编程方法。二、实验原理 1. HC-SR04超声波测距模块原理 HC-SR04超声波测距模块可提供2cm - 400cm的非接触式距离感测功能,测距精…...