STL算法之sort
STL所提供的各式各样算法中,sort()是最复杂最庞大的一个。这个算法接受两个RandomAccessIterators(随机存取迭代器),然后将区间内的所有元素以渐增方式由小到大重新排列。还有一个版本则是允许用户指定一个仿函数代替operator<作为排序标准。STL的所有关联式容器(associative containers)都拥有自动排序功能(底层结构为RB-tree,见STL关联式容器介绍_stl 关联式容器-CSDN博客),所以不需要用到这个sort算法。至于序列式容器(sequence containers)中的stack,queue和priority-queue都有特别的入口,不允许用户对元素排序。剩下vector、dequeue和list,前两者的迭代器属于RandomAccessIterators,适合使用sort算法,list的迭代器则属于BidirectionalIterators,都不适合使用sort算法。如果要对list或slist排序,应该使用它们自己提供的成员函数sort()。稍后我们便可以看到为什么泛型算法sort()一定要求RandomAccessIterators。
排序有多么重要
人类生活在一个有序的世界中。没有排序,很多事情无法进行。排过序的数据,特别容易查找。电话簿总是以人名为键值来排序,对人名而言,电话簿是有序的,对电话号码而言,电话簿是无序的。在电话簿里找一个人(从而得到他的电话号码)很容易,但我们能想象再电话簿里头不通过人名查找某个特定的电话号码吗?
这类情况大量发生在日常生活中。字典需要排序,书籍索引需要排序,磁盘目录需要排序,名片需要排序,图书馆藏需要排序,户籍数据需要排序。任何数据只要你想快速查找,具需要排序。
犹有进者,排序可能使其他工作更快更轻松。如果你要确定(或找出)一堆数据里头没有有重复的元素,先排序一遍再找,会比闷着头两两比对快快得多。换句话说,许多算法可能因为数据先行排序过而大幅改善效率。排序的成本,成为影响执行时间的关键因素。
STL算法的sort算法,数据量大时采用Quik Sort,分段递归排序。一旦分段后的数据量小于某个门槛,为了避免Quik Sort的递归调用带来过多额外负担(overhead),就改用Insertion Sort。如果递归层次过深,还会改用Heap Sort参见STL序列式容器之heap(堆)_stl 堆-CSDN博客 。以下分别介绍Quick Sort和Insertion Sort,然后再整合起来介绍STL sort算法。
Insertion Sort
Insertion Sort以双层循环的形式进行。外循环遍历整个序列,每次迭代决定出一个子区间;内循环遍历子区间,将子区间内的每一个“逆转对(inversion)”倒转过来。所谓“逆转对”是指任何两个迭代器i、j,i<j,而*i>*j。一旦不存在逆转对,序列即排序完毕。这个算法的时间复杂度为,说起来并不理想,但是当数据量很少时,却有不错的效果,原因是实现上有一些技巧(稍后源代码可见),而且不像其它比较复杂的排序算法有着诸如递归调用等操作带来的额外负担。下图是Insertion Sort的详细步骤示意:
图中左下部分的三角形内部,每一行都是有序的序列;每次往有序序列中增加一个元素,依次采用插入到正好使序列依然保持有序状态的方式进行;固而得名插入排序(Insertion Sort)。
SGI STL的Insert Sort有两个不同的版本,一个使用默认的operator<,另个使用仿函数comp代替。以下列出版本一。由于STL规格并不开放Insert Sort,所以SGI将以下函数的名称都加上了双下划线,表示内部使用。
//版本一
template <class RandomAccessIterator>
void __intertion_sort(RandomAccessIterator first, RandomAccessIterator last) {if (first == last) return ;for (RandomAccessIterator I = first + 1, I != last; ++I) __linear_insert(first, I, value_type(first));
}template <class RandomAccessIterator, class T>
void __linear_insert(RandomAccessIterator first, RandomAccessIterator last, T*) {T value = *last;if (value < *first) {copy_backward(first, last, last+1); // 当前最后一个元素比原有序序列,最小元素还小*first = value; // 将原序列,往后移一个位置,将新的最小元素放置到最前面} else__unguarded_linear_inserrt(last, value);}template <class RandomAccessIterator, class T>
void __unguarded_linear_inserrt(RandomAccessIterator last, T value) {RandomAccessIterator next = last;--next;while(value < *next) { // 新加入的元素比当前元素小,*last = *next; // 则将当前元素往后挪,否则就再该位置填入新加入的值last = next;--next;}*last = value;
}
上述函数之所以命名为unguarded_x是因为,一般的Insert Sort在内循环原本需要做两次判断,判断是否相邻两元素使“逆转对”,同时也判断循环是否超过边界。但由于上述所示的代码会导致最小值必然在内循环子区间的最边缘,所以两个判断可合为一个判断,所以成为unguarded_。省下一个判断操作,乍见之下无足轻重,但是在大数据量的情况下,影响还是可观的,毕竟这是一个非常根本的算法核心,在大数据量的情况下(大量调用?),提效会非常惊人。
稍后出场的几个函数,也有以unguarded_为前缀命名者,同样是在特定情况下,边界条件的检验可以省略(或说已融入特定条件之内)。
Quick Sort
如果我们拿Insertion Sort来处理大量数据,其的复杂度就令人摇头了。大数据量的情况下有许多更好的排序可供选择。正如其名称所昭示,Quik Sort是目前已知最快的排序法,平均复杂度为
,最坏情况下将达到
。不过IntroSort(极类似 median-of-three QuickSort的一种排序算法)可将最坏情况推进到
。早期的STL sort算法都采用Quick Sort,SGI STl已改用IntroSort。
Quick Sort算法可以叙述如下。假设S代表将被排序的序列:
- 如果S的元素个数为0或1,结束。
- 取S中的任何一个元素,当做枢轴(pivot)v。
- 将S分割为L,R两段,使L内的每一个元素都小于或等于v,R内的每一个元素大于或等于v。
- 对L,R递归执行Quick Sort
Quick Sort的精神在于将大区间分割为小区间,分段排序。每一个小区间排序完成后,串接起来的大区间也就完成了排序。最坏的情况下发生在分割(partition)时产生出一个空的子区间--那完全没有达到分割的预期效果。下图说明了Quick Sort的分段排序过程
Median-of-Three(三点中值)
注意任何一个元素度可以被选来当做枢轴(pivot),但是其合适与否却影响Quick Sort的效率,为了避免“元素当初输入时不够随机”所带来的恶化效应,最理想最稳当的方式就是取整个序列的头、尾、中央三个位置的元素,以其中值(median)作为枢轴。这种做法称为median-of-three partition,或称为mediun-of-three-QuickSort。为了能够快速取出中央位置的元素,显然随机迭代器必须能随机定位,亦即必须是个RandomAccessIterators。
以下是SGI STL提供的三点中值决定函数:
template<class T>
inline const T& __median(const T& a, const T& b, const T& c) {if (a < b) if (b < c) // a < b < creturn b;else if (a < c) return c; // a < b, b >= c, a < celse return a;else if (a < c) // c> a>= breturn a;else if (b < c) // a >= b, a>=c, b <creturn c;else return b;
}
Partition(分割)
分割方法不只一种,以下叙述既简单又有良好成效的做法。令头端迭代器first向尾端移动,尾端迭代器last向头部移动。当*first大于或等于枢轴时就停下来,当*last小于或等于枢轴时也停下来,然后检验两个迭代器是否交错。如果first仍然在左而last仍然在右,就两者元素互换,然后各自调整一个位置(向中央逼近),再继续进行相同的行为。乳沟发现两个迭代器交错了(亦即!(first < last)),表示整个序列已经调整完毕,以此时的first为轴,将序列分为左右两半,左半部分所有元素值都小于或等于枢轴,右半部分所有元素值都大于或等于枢轴。
下面SGI STL提供的分割函数,其返回值是分割后的有段第一个位置:
template<class RandomAcccessIterator, class T>
RandomAcccessIterator __unguarded_partion(RandomAcccessIterator first,RandomAcccessIterator last,T pivot) {while(true) {while(*first < pivot) ++first;--last;while(pivot < *last) --last;if (!(first < last)) return first;iter_swap(first, last);++first;}
}
下图是分割实例的完整过程:
threshold(阈值)
面对一个只有十来个元素的小型序列,使用Quick Sort这样复杂而(可能)需要大量运算的排序法,是否划算?不,不划算,在小数据量的情况下,甚至简单如Insert Sort者也可能快过Quick Sort--因为Quick Sort会为了极小的子序列产生许多的函数递归调用。
鉴于这种情况,适度评估序列的大小,然后决定采用Quick Sort或Insertion Sort,是值得采纳的一种优化措施。然后究竟多小的序列才应该断然改用Insertion Sort?并无定论,5~20都可能导致差不多的结果,实际的最佳值因设备而异。
final insertion sort
优化措施用不嫌多,只要我们不是贸然行事。如果我们令某个大小以下的序列滞留在"几近排序但尚未竟全功"的子序列做一次完整的排序,其效率一般认为会比“将所有子序列彻底排序”更好。这是以为Insertion Sort在面对“几近排序”的序列时,有很好的表现。
introsort
不当的枢轴选择,导致不当的分割。导致Quick Sort恶化未.David R. Musser于1996年提出易总混合式排序算法:Introspective Sorting(内省式排序),简称Intro Sort,其行为在大部分情况下几乎与median-of-3 Quick Sort 完全相同(当然也一样快)。但是当分割行为有恶化未二次行为的倾向时,能够自我侦测,转而改用Heap Sort,使效率维持在Heap Sort的
,又比一开始就使用Heap Sort来得好。稍后边可以看到SGI STL源代码中对IntroSort的实现。
SGI STL sort
下面是SGI STL sort()源代码
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {if (first != last) {__introsort_loop(first, last, value_type(first), __lg(last-first)*2);__final_insertion_sort(first, last);}
}
其中__lg()用来控制分割恶化的情况
// 找出2^k <= n 的最大值k,例:n=7,得k=2;n=20的k=4;n=8,得k=3
template <class Size>
inline Size __lg(Size n) {Size k;for (k = 0; n>1; n >>= 1) ++k;return k;
}
__introsort_loop() 最后一个参数表示递归的最深层次不应超过2*log(N),代码如下:
template <class RandomAccessIterator, class T, class Size>
void __introsort_loop(RandomAccessIterator first, RandomAccessIterator last, T*, Size depth_limit) {while ((last - first) > __stl_threshold) { // __stl_threashold = 16,全局常量if (depth_limit == 0) {partial_sort(first, last, last); // 改用heapsort} --depth_limit;RandomAccessIterator cut = __unguarded_partition(first, last, T(__median(*first,*(first + (last - first)/2),*(last-1))));// 右半段递归进行sort__introsort_loop(cut, last, value_type(first), depth_limit);last = cut;// 因为重置了last,所以左半段继续进行排序}
}
函数一开始判断序列的大小.__stl_threshold是个全局整型常数,定义如下
const int __stl_threshold = 16;
通过元素个数检验后,再检查分割层次。如果分割层次超过指定值,就改用partital_sort(), 事实上调用的是Heap Sort。
都通过了这些检验之后,便进入Quik Sort完全相同的程序:以median-of-3方法确定枢轴位置,然后调用__unguarded_partition()找出分割点,然后针对左右段递归进行IntroSort。
当__introsort_loop()结束,[first, last)内有多个“元素个数少于16”的子序列,每个子序列都有相当程度的排序,但尚未排序(以为元素个数一旦小于__stl_threshold,就被中止进一步的排序操作了)。回到母函数sort(),再进入__final_insertion_sort():
template <RandomAccessIterator>
void __final_insertion_sort(RandomAccessIterator first, RandomAccessIterator last) {if (last - first > __stl_threshold) { // 16__insertion_sort(first, first + __stl_threshold);__unguarded_insertion_sort(first + __stl_threshold, last);} else {__insertion_sort(first, last);}
}
此函数首先判断元素个数是否大于16.如果答案为否,就调用__insertion_sort()加以处理。如果答案为是,就将[first, last)分割为长度为16的一段子序列,和另一段剩余子序列,再针对两个子序列分别调用__insert_sort()和__unguarded_insertion_sort().前者代码已于先前展示,后者源代码如下:
template <RandomAccessIterator>
inline void __unguarded_insertion_sort(RandomAccessIterator first, RandomAccessIterator last) {__unguarded_insertion_sort_aux(first, last, value_type(first));
}template <RandomAccessIterator>
void __unguarded_insertion_sort_aux(RandomAccessIterator first, RandomAccessIterator last, T*) {for (RandomAccessIterator i = first, i != last; ++i) __unguarded_linear_insert(i, T(*i));
}
这就是SGI STL sort算法的完整过程。为了做个比较,我们再列出RW STL sort的部分源代码,RW版本用的是纯粹Quick Sort,不是Intro Sort
template <class RandomAccessIterator>
inline void sort(RandomAccessIterator first, RandomAccessIterator last) {if (!(first == last)) {__quick_sort_loop(first, last);__final_insertion_sort(first, last); //其内兼容于SGI STL完全相同}
}template <class RandomAccessIterator>
inline void __quick_sort_loop(RandomAccessIterator first, RandomAccessIterator last) {__quick_sort_loop_aux(first, last, _RWSTD_VALUE_TYPE(first));
}template <class RandomAccessIterator, class T>
inline void __quick_sort_loop_aux(RandomAccessIterator first, RandomAccessIterator last, T*) {while (last - first > __stl_threshold) {// median-of-3 partitioningRandomAccessIterator cut = __unguarded_partition(first, last, T(__median(*first, *(first + (last - first)/2), *(last - 1))));if (cut - first > last - cut) {__quick_sort_loop(cut, last); // 较短段以递归方式处理last = cut;} else {__quick_sort_loop(first, cut); // 较短段以递归方式处理first = cut;}}
}
参考文档《STL源码剖析--侯捷》
相关文章:
STL算法之sort
STL所提供的各式各样算法中,sort()是最复杂最庞大的一个。这个算法接受两个RandomAccessIterators(随机存取迭代器),然后将区间内的所有元素以渐增方式由小到大重新排列。还有一个版本则是允许用户指定一个仿函数代替operator<作为排序标准。STL的所有…...
elementui table滚动分页加载
文章目录 概要 简化的实现示例: 小结 概要 在使用 Element UI 的 Table 组件时,如果需要实现滚动分页加载的功能,可以通过监听 Table 的滚动事件来动态加载更多数据。 简化的实现示例: <template><el-table ref"…...
【MySQL 进阶之路】索引的使用
5.索引的使用规则 在数据库管理系统(DBMS)中,索引是提高查询效率的关键机制之一。MySQL索引优化是指通过设计、调整和选择合适的索引策略,以提高数据库的查询性能和降低资源消耗。以下是一些关键的索引使用规则: 1. …...
FPGA中所有tile介绍
FPGA中包含的tile类型,以xinlinx 7k为例,可以通过f4pga项目中的原语文件夹查看,主要包含以下这些: 以下是您提到的 Xilinx 7 系列 FPGA 中各种模块的含义及用途: 1. BRAM (Block RAM) BRAM 是 FPGA 中的块存储资源&…...
理解 Python PIL库中的 convert(‘RGB‘) 方法:为何及如何将图像转换为RGB模式
理解 Python PIL库中的 convert(RGB) 方法:为何及如何将图像转换为RGB模式 在图像处理中,保持图像数据的一致性和可操作性是至关重要的。Python的Pillow库(继承自PIL, Python Imaging Library)提供了强大的工具和方法来处理图像&…...
LVS默认的工作模式支持哪些负载均衡算法?
LVS默认的工作模式支持哪些负载均衡算法? LVS(Linux Virtual Server)默认支持多种负载均衡算法,这些算法在不同的场景下具有各自的优势。以下是 LVS 默认支持的负载均衡算法及其特点: 1. 轮询调度(Round Robin Sched…...
C/C++中的调用约定
在C/C编程中,调用约定(calling conventions)是一组指定如何调用函数的规则。主要在你调用代码之外的函数(例如OS API,操作系统应用程序接口)或OS调用你(如WinMain的情况)时起作用。如果编译器不知道正确的调用约定,那么你很可能会遇到非常奇怪…...
RAG评估指南:从检索到生成,全面解析LLM性能评估方法
前言 这一节我们将从时间线出发对RAG的评估方式进行对比,这些评估方式不仅限于RAG流程之中,其中基于LLM的评估方式更加适用于各行各业。 RAG常用评估方式 上一节我们讲了如何用ROUGE 这个方法评估摘要的相似度,由于篇幅限制,没…...
极兔速递开放平台快递物流查询API对接流程
目录 极兔速递开放平台快递物流查询API对接流程API简介物流查询API 对接流程1. 注册用户2. 申请成为开发者3. 企业认证4. 联调测试5. 发布上线 签名机制详解1. 提交方式2. 签名规则3. 字段类型与解析约定 物流轨迹服务极兔快递单号查询的其他方案总结 极兔速递开放平台快递物流…...
FFmpeg:强大的音视频处理工具指南
FFmpeg:强大的音视频处理工具指南 1. FFmpeg简介2. 核心特性2.1 基础功能2.2 支持的格式和编解码器 3. 主要组件3.1 命令行工具3.2 开发库 4. 最新发展5. 安装指南5.1 Windows系统安装5.1.1 直接下载可执行文件5.1.2 使用包管理器安装 5.2 Linux系统安装5.2.1 Ubunt…...
项目集成篇:springboot集成redistemple实现自定义缓存,并且可以设置过期时间
在Spring Boot中集成Redis并使用RedisTemplate实现自定义缓存功能,同时能够设置缓存项的过期时间,可以通过以下步骤来完成。我们将创建一个服务层方法,该方法将使用RedisTemplate直接与Redis交互,并为每个缓存项设置特定的过期时间…...
ClickHouse守护进程
背景描述 维护CK过程中,有时候会有CK OOM,并且CK自己没有自动拉起的情况出现;那么这个时候就需要守护进程,最初我不说了Supervisor来做守护进程,但是当我手动kill的时候发现并没有自动拉起。 解决方案 于是乎自己写…...
【Vivado】xdc约束文件编写
随手记录一下项目中学到的约束文件编写技巧。 时序约束 创建生成时钟 参考链接: Vivado Design Suite Tcl Command Reference Guide (UG835) Vivado Design Suite User Guide: Using Constraints (UG903) 通过Clocking Wizard IP创建的时钟(MMCM或…...
Nginx静态资源配置
基本配置原则 明确资源目录:为不同类型的静态资源指定不同的路径,这样可以避免路径冲突,并且便于管理。正确设置文件权限:确保 Nginx 具有读取静态资源的权限。缓存优化:为静态资源设置缓存头(如 expires&…...
365天深度学习训练营-第P7周:马铃薯病害识别(VGG-16复现)
文为「365天深度学习训练营」内部文章 参考本文所写记录性文章,请在文章开头带上「👉声明」 🍺 要求: 自己搭建VGG-16网络框架【达成√】调用官方的VGG-16网络框架【达成√】如何查看模型的参数量以及相关指标【达成√】 &#…...
docker学习笔记(三)--容器数据卷
文章目录 一、数据卷的介绍二、简单用法--直接指定挂载路径三、具名挂载与匿名挂载具名挂载匿名挂载 一、数据卷的介绍 docker将应用和环境打包成一个镜像,形成一个容器运行。那么容器产生的数据,如果不通过docker commit命令提交生成新的镜像ÿ…...
联通光猫DT741-csf 完全po解 改桥接
1.管理员密码破解,把光猫的loid pppoe用户名密码,各个连接vlan id记下来 打开链接 http://192.168.1.1/hidden_version_switch.html version选择Default Version,点击submit,光猫默认重启。重启后ip地址变为192.168.1.1 并且dhcp…...
Java Web 2 JS Vue快速入门
一 JS快速入门 1.什么是JavaScript? 页面交互: 页面交互是指用户与网页之间的互动过程。例如,当用户点击一个按钮,网页会做出相应的反应,如弹出一个对话框、加载新的内容或者改变页面的样式等;当用户在表…...
【数据结构】动态规划-基础篇
针对动态规划问题,我总结了以下5步: 确定dp数组以及下标的含义; 递推公式; dp数组如何初始化; 遍历顺序; 打印dp数组(用来debug); 以上5步适用于任何动态规划问题&#x…...
从watch、watchEffect、useEffect原理到vue、react响应原理
正文 1.核心原理 Vue中的watch、watchEffect是基于Vue的响应式系统(Proxy),依赖于ref或reactive数据的变化。React中的useEffect基于状态驱动的重新渲染机制,通过依赖数组 [dependency],手动声明需要追踪的状态或属性…...
Cursor+Devbox AI开发快速入门
1. 前言 今天无意间了解到 Cursor 和 Devbox 两大开发神器,初步尝试以后发现确实能够大幅度提升开发效率,特此想要整理成博客以供大家快速入门. 简单理解 Cursor 就是一款结合AI大模型的代码编辑器,你可以将自己的思路告诉AI,剩下的目录结构的搭建以及项目代码的实现均由AI帮…...
SpringBoot+MyBatis整合ClickHouse实践
整合Spring Boot、MyBatis和ClickHouse可以让你使用Java开发的应用程序高效地与ClickHouse数据库进行交互。以下是一个基本的步骤指南,帮助你完成这个整合过程: 1. 添加依赖 首先,在你的pom.xml文件中添加必要的Maven依赖。你需要引入Sprin…...
在数据库设计中同步冗余字段的思考与实践
目录 前言1. 冗余字段设计的背景与场景1.1 场景描述1.2 冗余字段的必要性 2. 冗余字段设计的优点2.1 提高查询效率2.2 简化应用逻辑 3. 冗余字段设计的缺点与挑战3.1 数据不一致问题3.2 更新开销增加3.3 数据冗余占用存储空间 4. 如何同步更新冗余字段4.1 手动更新方式4.2 使用…...
MacOS安装sshfs挂载远程电脑硬盘到本地
文章目录 sshfs简介sshfs安装下载安装macFUSE安装sshfs sshfs使用注意事项 sshfs简介 SSHFS(SSH Filesystem)是一种基于FUSE(用户空间文件系统)的文件系统,它允许你通过SSH协议挂载远程文件系统。使用SSHFS࿰…...
6.824/6.5840(2024)环境配置wsl2+vscode
本文是经过笔者实践得出的最速の环境配置 首先,安装wsl2和vscode 具体步骤参见Mit6.s081环境配置踩坑之旅WSL2VScode_mit6s081-CSDN博客 接下来开始为Ubuntu(笔者使用的版本依然是20.04)配置go的相关环境 1、更新Ubuntu的软件包 sudo apt-get install build-es…...
查询产品所涉及的表有(product、product_admin_mapping)
文章目录 1、ProductController2、AdminCommonService3、ProductApiService4、ProductCommonService5、ProductSqlService1. 完整SQL分析可选部分(条件筛选): 2. 涉及的表3. 总结4. 功能概述 查询指定管理员下所有产品所涉及的表?…...
C# 冒泡的算法
C# 冒泡的算法 public void BubbleSort(int[] arr) {int temp;for (int j 0; j < arr.Length - 2; j){for (int i 0; i < arr.Length - 2; i){if (arr[i] > arr[i 1]){temp arr[i 1];arr[i 1] arr[i];arr[i] temp;}}} }使用方法 int[] array new int[] { 5,…...
前端上传后端接收参数为null
记录一下工作中的问题 前端明明把文件传到后台了,但是后台接收参数为null 原因: 前端上传文件的name和后端接收参数名称不匹配 前端 后端 把前端上传的name由upfile改为file即可 本来是很基本的小问题,但因为自己钻了牛角尖一直没搞定&…...
思考:如何把知识更轻松的传递给别人
为什么我会来思考这个问题呢,我想要把我学到的东西传递给其他人,也就是能够成为一个老师,我曾多次尝试解决问题,但是事情总是不如我所愿。现在我进行一定的总结,来复盘一下我的教授过程。 在学生面对新鲜事物的同时&am…...
BERT的中文问答系统50
我们将对BERT的中文问答系统48-1代码进行以下改进: 1.增加时间日期和日历功能:在GUI中增加显示当前时间和日期的功能,并提供一个日历组件。 2.增加更多模型类型:增加娱乐、电脑、军事、汽车、植物、科技、历史(朝代、皇帝)、名人、生活(出行、菜品、菜谱、居家),法律、…...
node.js实现分页,jwt鉴权机制,token,cookie和session的区别
文章目录 1. 分⻚功能2. jwt鉴权机制1.jwt是什么2.jwt的应用3.优缺点 3. cookie,token,session的对比 1. 分⻚功能 为什么要分页 如果数据量很⼤,⽐如⼏万条数据,放在⼀个⻚⾯显⽰的话显然不友好,这时候就需要采⽤分⻚…...
OpenHarmony-4.GPIO驱动
GPIO 1.功能简介 GPIO(General-purpose input/output)即通用型输入输出。GPIO又俗称为I/O口,I指的是输入(in),O指的是输出(out)。可以通过软件来控制其输入和输出,即I/O控制。通常&…...
static关键字在嵌入式C编程中的应用
目录 一、控制变量的存储周期和可见性 1.1. 局部静态变量 1.2. 全局静态变量 二、控制函数的可见性 2.1. 静态函数 2.2. 代码示例(假设有两个文件:file1.c和file2.c) 三、应用场景 3.1. 存储常用数据 3.2. 实现内部辅助函数 四、注…...
图形开发基础之在WinForms中使用OpenTK.GLControl进行图形绘制
前言 GLControl 是 OpenTK 库中一个重要的控件,专门用于在 Windows Forms 应用程序中集成 OpenGL 图形渲染。通过 GLControl,可以轻松地将 OpenGL 的高性能图形绘制功能嵌入到传统的桌面应用程序中。 1. GLControl 的核心功能 OpenGL 渲染上下文&…...
macOS sequoia 15.1中应用程序“程序坞”没有权限打开
在macOS sequoia 15.1版本中新安装的应用程序在访达中打开报错显示应用程序“程序坞”没有权限打开“(null)”。 解决办法 在启动台中找到终端,点击打开,切换到应用目录下,输入 cd /Applications/ 找到需要打开的应用程序目录࿰…...
汉诺塔递归问题(C++)
汉诺塔递归问题 汉诺塔是典型的递归问题,这个问题可以这样描述: 完成目标: 将n个盘子从A搬运到C,求需要移动多少次完成? **约束条件:**搬运的过程中每次只能移动一个盘子,且不能出现大的盘子…...
【开源】A060-基于Spring Boot的游戏交易系统的设计与实现
🙊作者简介:在校研究生,拥有计算机专业的研究生开发团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看项目链接获取⬇️,记得注明来意哦~🌹 赠送计算机毕业设计600个选题ex…...
抖音SEO短视频矩阵源码私有化部署
为了开发一套高效的抖音短视频SEO矩阵系统,开发者需要掌握以下核心技术: 网络编程:具备使用Python、Java或其他编程语言进行网络编程的能力,能够利用爬虫技术从抖音平台获取数据。 数据处理:熟悉并能够应用数据处理工…...
深入浅出:Python 编程语言的学习之路
文章目录 1. Python 简介2. Python 的安装与环境配置2.1 安装 Python2.2 配置开发环境 3. Python 基础语法3.1 变量与数据类型示例代码:定义变量 3.2 控制结构示例代码:条件语句示例代码:循环语句 3.3 函数与模块示例代码:定义函数…...
R语言机器学习论文(三):特征提取
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据一、数据归一化二、离散型分类变量的编码三、筛选特征四、重要特征五、输出结果六、总结系统信息介绍 在数据分析和机器学习项目中,经常需要对数据进行预…...
【C#设计模式(17)——迭代器模式(Iterator Pattern)】
前言 迭代器模式可以使用统一的接口来遍历不同类型的集合对象,而不需要关心其内部的具体实现。 代码 //迭代器接口 public interface Iterator {bool HashNext();object Next(); } //集合接口 public interface Collection {Iterator CreateIterator(); } //元素迭…...
【云原生系列】云计算中的负载均衡是什么,有什么用
云计算里有一个非常重要的概念叫“负载均衡”,如果你经常听到这个词但还不太明白具体是怎么回事,这篇文章可以给你一些思路。负载均衡简单来说就是“分担压力”,确保访问量被合理地分配到各个服务器上,让系统高效且稳定地运行。 …...
笔记本电脑usb接口没反应怎么办?原因及解决方法
笔记本电脑的USB接口是我们日常使用中非常频繁的一个功能,无论是数据传输、充电还是外接设备,都离不开它。然而,当USB接口突然没有反应时,这无疑会给我们的工作和学习带来不小的困扰。下面,我们就来探讨一下笔记本USB接…...
容器运行应用及Docker命令
文章目录 一、使用容器运行Nginx应用1_使用docker run命令运行Nginx应用1 观察下载容器镜像过程2 观察容器运行情况 2_访问容器中运行的Nginx服务1 确认容器IP地址2 容器网络说明3 使用curl命令访问 二、Docker命令1_Docker命令获取帮助方法2_Docker官网提供的命令说明3_docker…...
PETRv2: A Unified Framework for 3D Perception from Multi-Camera Images
全文摘要 本文介绍了一种名为PETRv2的统一框架,用于从多视图图像中进行三维感知。该框架基于先前提出的PETR框架,并探索了时间建模的有效性,利用前一帧的时间信息来提高三维物体检测效果。作者在PETR的基础上扩展了三维位置嵌入(…...
Python库常用函数-数据分析
Python库常用函数 1.pandas库 (1)数据读取与写入 读取 CSV 文件: data pd.read_csv(file.csv)读取 Excel 文件: data pd.read_excel(file.xlsx, sheet_nameSheet1)写入 CSV 文件: data.to_csv(new_file.csv, ind…...
【机器学习】机器学习的基本分类-监督学习-随机森林(Random Forest)
随机森林是一种基于集成学习(Ensemble Learning)思想的算法,由多个决策树构成。它通过结合多棵决策树的预测结果来提升模型的泛化能力和准确性,同时减少过拟合的风险。 1. 随机森林的核心思想 多样性: 随机森林通过引…...
Java入门:22.集合的特点,List,Set和Map集合的使用
1 什么是集合 本质就是容器的封装,可以存储多个元素 数组一旦创建,长度就不能再改变了。 数组一旦创建,存储内容的类型不能改变。 数组可以存储基本类型,也可以存储引用类型。 数组可以通过length获得容量的大小,但…...
Web3与区块链如何通过智能合约实现自动化生态?
Web3和区块链正在重塑互联网的未来,其核心在于去中心化和用户数据自主权。而作为区块链技术的重要组成部分,智能合约通过自动执行预设规则,大大提升了效率和安全性。本文将探讨Web3与区块链如何通过智能合约实现生态的自动化。 什么是智能合约…...
排序算法入门:分类与基本概念详解
引言 排序是编程世界中最常见的操作之一,也是许多算法的基础。不管是从数据中找出最大值还是将一堆乱序的名字整理得井井有条,排序算法都在幕后默默工作。你可能会觉得排序很简单:从小到大排个序而已嘛。但当数据量大到上百万、上亿…...