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

C++ 二分查找:解锁高效搜索的密码

一、引言

在 C++ 编程的广阔领域中,数据处理和查找是日常开发中极为常见的操作。想象一下,你有一个包含数百万个数据的有序数组,需要从中快速找到特定的元素,如果采用逐个遍历的方式,效率之低可想而知,而二分查找(Binary Search)算法就如同一位高效的 “数据侦探”,能在有序数组中迅速定位目标元素 ,大大提高查找效率。它的核心优势在于,每一次比较都能将搜索范围减半,使得查找速度大幅提升,时间复杂度降低至 O (log n)。

二分查找在诸多实际场景中都有着广泛应用。在搜索引擎中,当用户输入关键词进行搜索时,背后可能就用到了类似二分查找的机制,从海量的索引数据中快速定位相关信息;在数据库索引中,二分查找帮助数据库管理系统迅速定位到所需的数据记录,从而实现高效的数据查询;在游戏开发中,比如根据玩家的等级在有序的奖励列表中查找对应的奖励,二分查找也能派上用场 。

在 C++ 语言中,掌握二分查找算法不仅是提升编程技能的关键,更是理解算法思想、优化程序性能的重要一步。无论是初学者探索编程世界,还是经验丰富的开发者追求代码的极致效率,二分查找都值得深入学习和研究。接下来,让我们一同揭开 C++ 二分查找的神秘面纱,深入探索其原理、实现及应用。

二、二分查找基础

2.1 定义与原理

二分查找,也被称为折半查找,是一种基于分治策略的高效查找算法 。其核心原理是利用数组的有序性,在每次比较中,将搜索区间缩小一半,从而快速逼近目标元素。例如,在一个升序排列的数组中查找目标值,首先选取数组的中间元素与目标值进行比较。若中间元素等于目标值,则查找成功;若中间元素大于目标值,说明目标值在数组的左半部分,此时将搜索区间缩小到左半部分;若中间元素小于目标值,表明目标值在数组的右半部分,将搜索区间缩小到右半部分 。通过不断重复上述过程,直到找到目标元素或者确定目标元素不存在于数组中。

2.2 适用条件

二分查找有一个严格的前提条件,即数组必须是有序的。这是因为二分查找依赖于通过比较中间元素与目标值来确定搜索方向,如果数组无序,这种比较就无法有效地缩小搜索范围。例如,对于一个乱序数组[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5],如果要查找元素5,无法直接通过二分查找的方式,因为无法确定中间元素5与目标值5的位置关系,也就不能确定下一步的搜索区间。只有当数组有序,如变为[1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]时,才能运用二分查找算法高效地查找目标元素 。

2.3 工作流程

下面以在有序数组[1, 3, 5, 7, 9, 11, 13]中查找目标值7为例,详细介绍二分查找的工作流程:

  1. 初始化指针:设置左指针left指向数组的起始位置,即left = 0;设置右指针right指向数组的末尾位置,即right = 6(数组长度为 7,索引从 0 开始),此时搜索区间为整个数组[0, 6]。
  1. 计算中点:计算中间位置的索引mid,公式为mid = left + (right - left) / 2 。在第一次计算时,mid = 0 + (6 - 0) / 2 = 3,即中间元素为7。
  1. 比较元素并调整查找区间:将中间元素arr[mid](即7)与目标值7进行比较,发现二者相等,查找成功,返回mid的值3,即找到了目标元素7在数组中的索引位置 。

再以查找目标值4为例,看一下查找失败的情况:

  1. 同样初始化left = 0,right = 6,计算mid = 0 + (6 - 0) / 2 = 3,中间元素arr[mid] = 7。
  1. 因为7 > 4,所以目标值在左半部分,更新右指针right = mid - 1 = 2,此时搜索区间变为[0, 2]。
  1. 重新计算mid = left + (right - left) / 2 = 0 + (2 - 0) / 2 = 1,中间元素arr[mid] = 3。
  1. 由于3 < 4,目标值在右半部分,更新左指针left = mid + 1 = 2,搜索区间变为[2, 2]。
  1. 再次计算mid = left + (right - left) / 2 = 2 + (2 - 2) / 2 = 2,中间元素arr[mid] = 5。
  1. 因为5 > 4,更新右指针right = mid - 1 = 1,此时left = 2,right = 1,left > right,搜索区间为空,说明目标元素4不存在于数组中,返回 -1 表示查找失败。

三、C++ 代码实现

3.1 基本代码框架

下面是用 C++ 实现二分查找的基本代码:

 

#include <iostream>

#include <vector>

// 二分查找函数,返回目标值的索引,若未找到返回 -1

int binarySearch(const std::vector<int>& arr, int target) {

int left = 0; // 左指针,初始指向数组开头

int right = arr.size() - 1; // 右指针,初始指向数组末尾

while (left <= right) {

int mid = left + (right - left) / 2; // 计算中间位置,防止(left + right)溢出

if (arr[mid] == target) {

return mid; // 找到目标值,返回其索引

}

else if (arr[mid] > target) {

right = mid - 1; // 目标值在左半部分,更新右指针

}

else {

left = mid + 1; // 目标值在右半部分,更新左指针

}

}

return -1; // 未找到目标值,返回 -1

}

3.2 代码详解

  1. 函数定义与参数
 

int binarySearch(const std::vector<int>& arr, int target)

函数名为binarySearch,返回类型为int ,用于返回目标值在数组中的索引,如果未找到则返回 - 1。它接受两个参数,一个是const std::vector<int>& arr,表示一个常量引用的整数向量,即我们要查找的有序数组;另一个是int target,表示要查找的目标值。

2. 变量初始化

 

int left = 0;

int right = arr.size() - 1;

定义并初始化两个指针,left初始化为 0,指向数组的起始位置;right初始化为arr.size() - 1,指向数组的末尾位置,这两个指针定义了当前的搜索区间。

3. 循环结构

 

while (left <= right) {

// 循环体

}

使用while循环,只要left小于等于right,说明搜索区间不为空,就继续循环查找。

4. 中点计算

 

int mid = left + (right - left) / 2;

计算当前搜索区间的中间位置mid。采用left + (right - left) / 2的方式计算中点,而不是直接使用(left + right) / 2 ,这是为了防止left和right较大时,两者相加导致整数溢出。

5. 条件判断与指针移动

 

if (arr[mid] == target) {

return mid;

}

else if (arr[mid] > target) {

right = mid - 1;

}

else {

left = mid + 1;

}

如果arr[mid]等于target,说明找到了目标值,直接返回mid;如果arr[mid]大于target,说明目标值在左半部分,将右指针right移动到mid - 1;如果arr[mid]小于target,说明目标值在右半部分,将左指针left移动到mid + 1。

6. 未找到目标值的处理

 

return -1;

如果循环结束后仍未找到目标值,说明目标值不在数组中,返回 -1。

3.3 示例演示

 

int main() {

std::vector<int> arr = {1, 3, 5, 7, 9, 11, 13, 15};

int target = 7;

int result = binarySearch(arr, target);

if (result != -1) {

std::cout << "目标值 " << target << " 在数组中的索引是: " << result << std::endl;

}

else {

std::cout << "目标值 " << target << " 不在数组中" << std::endl;

}

return 0;

}

在上述示例中,定义了一个有序数组arr和目标值target,调用binarySearch函数进行查找。如果找到目标值,输出其在数组中的索引;如果未找到,输出提示信息。运行该程序,输出结果为:目标值 7 在数组中的索引是: 3 。

四、二分查找变体

4.1 查找第一个等于给定值的元素

在实际应用中,有时我们面对的有序数组存在重复元素 ,此时基本的二分查找只能找到其中一个等于目标值的元素,而我们可能需要找到第一个等于给定值的元素。例如,在一个成绩排名数组中,可能有多个学生的成绩相同,我们要找到第一个获得该成绩的学生的排名 。

实现这一变体的关键在于,当找到等于目标值的元素时,不能立即返回,而是要继续在左半部分查找,以确定是否还有更早出现的相同元素 。代码实现如下:

 

int binarySearchFirstEqual(const std::vector<int>& arr, int target) {

int left = 0;

int right = arr.size() - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (arr[mid] == target) {

// 如果mid是第一个元素或者前一个元素不等于target,说明找到第一个等于target的元素

if (mid == 0 || arr[mid - 1] != target) {

return mid;

} else {

// 否则继续在左半部分查找

right = mid - 1;

}

} else if (arr[mid] > target) {

right = mid - 1;

} else {

left = mid + 1;

}

}

return -1;

}

与基本二分查找相比,这段代码在找到arr[mid] == target时,增加了对mid位置的判断,以确定是否为第一个等于目标值的元素 。如果不是,则继续向左搜索,缩小右指针right,直到找到第一个等于目标值的元素或者搜索区间为空。

4.2 查找最后一个等于给定值的元素

类似地,查找最后一个等于给定值的元素也有其实际需求 。比如在统计学生成绩分布时,要确定最后一个获得某个特定成绩的学生的位置 。

实现思路是在找到等于目标值的元素后,继续在右半部分查找,判断是否还有更晚出现的相同元素 。代码如下:

 

int binarySearchLastEqual(const std::vector<int>& arr, int target) {

int left = 0;

int right = arr.size() - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (arr[mid] == target) {

// 如果mid是最后一个元素或者后一个元素不等于target,说明找到最后一个等于target的元素

if (mid == arr.size() - 1 || arr[mid + 1] != target) {

return mid;

} else {

// 否则继续在右半部分查找

left = mid + 1;

}

} else if (arr[mid] > target) {

right = mid - 1;

} else {

left = mid + 1;

}

}

return -1;

}

这里当arr[mid] == target时,通过判断mid是否为数组最后一个元素或者下一个元素是否不等于目标值,来确定是否为最后一个等于目标值的元素 。若不是,则更新左指针left,继续在右半部分查找。

4.3 查找第一个大于等于给定值的元素

在一些场景中,我们需要找到第一个大于等于给定值的元素 。例如,在一个商品价格列表中,要找到第一个价格大于等于预算的商品 。

实现时,当arr[mid] >= target时,需要判断mid是否为第一个元素或者前一个元素是否小于目标值 。如果满足条件,则找到第一个大于等于目标值的元素;否则继续向左搜索 。代码如下:

 

int binarySearchFirstGreaterEqual(const std::vector<int>& arr, int target) {

int left = 0;

int right = arr.size() - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (arr[mid] >= target) {

// 如果mid是第一个元素或者前一个元素小于target,说明找到第一个大于等于target的元素

if (mid == 0 || arr[mid - 1] < target) {

return mid;

} else {

// 否则继续在左半部分查找

right = mid - 1;

}

} else {

left = mid + 1;

}

}

return -1;

}

这段代码在arr[mid] >= target时,通过特定条件判断找到第一个大于等于目标值的元素,若不满足条件则调整右指针继续查找 。

4.4 查找最后一个小于等于给定值的元素

查找最后一个小于等于给定值的元素也有广泛应用 。比如在一个员工绩效评分列表中,要找到最后一个评分小于等于某个标准的员工 。

实现方法是当arr[mid] <= target时,判断mid是否为最后一个元素或者后一个元素是否大于目标值 。如果满足条件,则找到最后一个小于等于目标值的元素;否则继续向右搜索 。代码如下:

 

int binarySearchLastLessEqual(const std::vector<int>& arr, int target) {

int left = 0;

int right = arr.size() - 1;

while (left <= right) {

int mid = left + (right - left) / 2;

if (arr[mid] <= target) {

// 如果mid是最后一个元素或者后一个元素大于target,说明找到最后一个小于等于target的元素

if (mid == arr.size() - 1 || arr[mid + 1] > target) {

return mid;

} else {

// 否则继续在右半部分查找

left = mid + 1;

}

} else {

right = mid - 1;

}

}

return -1;

}

在这个代码中,当arr[mid] <= target时,通过条件判断确定是否为最后一个小于等于目标值的元素,若不是则更新左指针继续查找 。

五、复杂度分析

5.1 时间复杂度

二分查找的时间复杂度为 O (log n),这是由其算法特性决定的 。在二分查找过程中,每次比较都能将搜索区间缩小一半 。例如,对于一个长度为 n 的有序数组,第一次比较后,搜索区间缩小为 n/2;第二次比较后,搜索区间缩小为 n/4;以此类推 。假设需要比较 k 次才能找到目标元素或者确定目标元素不存在,那么有 n / 2^k = 1(当搜索区间缩小到只剩下一个元素时),通过求解这个等式,可得 2^k = n,进一步推出 k = log₂n 。这表明在最坏情况下,二分查找需要进行 log₂n 次比较,所以其时间复杂度为 O (log n) 。这种对数级别的时间复杂度,使得二分查找在处理大规模数据时,效率远高于线性查找的 O (n) 时间复杂度 。例如,当 n = 1000000 时,线性查找在最坏情况下需要比较 1000000 次,而二分查找最多只需要比较约 20 次(log₂1000000 ≈ 20) 。

5.2 空间复杂度

二分查找的空间复杂度为 O (1) 。在整个算法执行过程中,除了输入的数组本身,只使用了几个额外的变量,如左指针left、右指针right和中间位置mid 。这些变量所占用的空间是固定的,不会随着输入数据规模 n 的增大而增加 。无论数组的长度是多少,都只需要这几个变量来辅助完成查找操作,所以空间复杂度为常数级别的 O (1) 。这使得二分查找在空间利用上非常高效,尤其适用于对空间资源有限制的场景 。

六、注意事项与易错点

6.1 边界条件处理

在实现二分查找时,边界条件的处理至关重要,稍有不慎就会导致错误结果或无限循环 。

  1. 循环终止条件:循环终止条件应确保在查找区间为空时停止循环 。通常使用while (left <= right)作为循环条件,当left > right时,说明查找区间为空,循环结束 。如果错误地使用while (left < right),可能会导致遗漏最后一个元素的检查 。例如,在数组[1, 2]中查找元素2,如果使用while (left < right),第一次循环计算mid = 0,arr[mid] = 1 < 2,更新left = mid + 1 = 1,此时left < right条件不再满足,循环结束,会错误地认为元素2不存在 。
  1. 中间位置计算:计算中间位置时,使用mid = left + (right - left) / 2而不是mid = (left + right) / 2,这是为了防止left和right较大时,left + right导致整数溢出 。例如,当left和right都接近int类型的最大值时,left + right可能会超出int的取值范围,而left + (right - left) / 2则不会出现这种情况 。
  1. 指针更新:在更新左指针left和右指针right时,要确保指针移动的正确性 。当arr[mid] > target时,更新right = mid - 1;当arr[mid] < target时,更新left = mid + 1 。如果错误地写成right = mid或left = mid,可能会导致循环无法结束或错过目标元素 。比如在查找第一个等于给定值的元素变体中,当找到arr[mid] == target时,需要继续向左查找,此时应更新right = mid - 1,而不是right = mid,否则可能会错过第一个等于目标值的元素 。

6.2 数据类型与溢出问题

  1. 数据类型选择:在进行二分查找时,要根据数据的范围和实际需求选择合适的数据类型 。如果数据范围较大,使用int类型可能会导致数据溢出,此时应考虑使用long long等更大范围的数据类型 。例如,在处理大规模数据的索引时,若数据量超过int类型的表示范围,就需要使用long long来存储数组的索引和中间位置等变量 。
  1. 整数溢出:除了计算中间位置时可能出现整数溢出外,在其他涉及数值计算的地方也需要注意 。例如,在计算数组的长度或者索引时,如果进行了乘法、加法等运算,要确保结果不会超出数据类型的范围 。假设数组的索引从0开始,长度为n,如果在计算某个索引值时,使用了类似index = start + step * count的表达式,当step和count较大时,step * count可能会导致整数溢出 。
  1. 安全的中点计算方法:除了前面提到的mid = left + (right - left) / 2,还可以使用位运算mid = left + ((right - left) >> 1)来计算中点 。>>是右位移运算符,将(right - left)右移一位,相当于除以 2,这种方式在某些情况下效率更高,同时也能避免整数溢出问题 。例如,在一些对性能要求较高的算法竞赛或实际应用场景中,使用位运算计算中点可以在保证正确性的同时提升程序的运行效率 。

七、应用场景

7.1 数据结构中的应用

  1. 有序数组:在有序数组中,二分查找是一种极其高效的查找方式 。例如,在一个存储学生成绩的有序数组中,成绩按照从低到高排列 。当需要查找某个特定成绩的学生时,使用二分查找可以快速定位到该成绩在数组中的位置 。假设数组scores = [50, 60, 70, 80, 90, 95],要查找成绩为 80 的学生,通过二分查找,只需几次比较就能确定其位置,而如果采用线性查找,在数组较大时效率会很低 。
  1. 有序链表(通过改造):虽然二分查找通常适用于数组,但对于有序链表,通过一些改造也能应用二分查找思想 。由于链表不能像数组那样直接通过下标访问中间元素,需要通过遍历链表来确定中间位置 。可以使用快慢指针的方法,快指针每次移动两步,慢指针每次移动一步,当快指针到达链表末尾时,慢指针正好指向链表的中间位置 。然后根据中间元素与目标值的比较结果,决定在链表的前半部分还是后半部分继续查找 。不过,由于链表的遍历特性,这种方式的时间复杂度仍会比在数组中使用二分查找高一些 。例如,在一个有序的学生信息链表中,每个节点存储学生的姓名和成绩,要查找成绩为特定值的学生信息,就可以通过这种改造后的二分查找思想来提高查找效率 。

7.2 算法竞赛中的应用

在算法竞赛中,二分查找常用于解决多种类型的问题:

  1. 搜索问题:如在给定的有序序列中搜索特定元素或满足特定条件的元素 。例如,给定一个有序数组,要求找出数组中第一个大于等于某个给定值的元素 。在竞赛题目中,可能会将这个问题与其他条件结合,如给定一系列商品价格,要求找出第一个价格大于等于预算且品牌为特定品牌的商品价格 。
  1. 最值问题:通过二分答案的方式解决 。例如,在 “吃香蕉” 问题中,珂珂要在给定时间内吃完若干堆香蕉,每小时吃香蕉的速度不同,要求找出能在规定时间内吃完所有香蕉的最小速度 。可以通过二分法在速度的可能取值范围内查找最小速度,每次判断当前速度是否能满足在规定时间内吃完香蕉的条件,从而缩小搜索范围 。
  1. 查找满足条件的边界问题:比如查找第一个错误的版本 。假设一系列软件版本从某个版本开始出现错误,前面的版本都正确,需要通过调用isBadVersion函数来判断版本是否错误,使用二分查找可以高效地找到第一个错误的版本 。

7.3 日常编程中的应用

在日常开发中,二分查找也有很多实际应用:

  1. 查找配置文件:在开发中,配置文件通常包含各种参数和设置,以文本形式存储,并且可能按某种规则有序排列 。当程序需要读取特定配置项时,可以使用二分查找来快速定位 。例如,一个游戏开发项目的配置文件中,按照功能模块分类存储各种配置,如画面设置、音效设置等,每个模块下的配置项按字母顺序排列 。当需要查找 “sound_volume”(声音音量)配置项时,就可以利用二分查找在配置文件中快速找到其对应的值 。
  1. 搜索数据库索引:数据库索引是一种数据结构,用于提高数据查询的效率 。许多数据库使用 B 树或 B + 树等数据结构来实现索引,这些结构本身具有有序性 。在查询数据时,数据库管理系统可以利用二分查找的思想在索引中快速定位到可能包含目标数据的位置 。例如,在一个电商数据库中,商品表按照商品 ID 建立索引,当查询某个特定商品 ID 的商品信息时,数据库会通过二分查找在索引中快速定位到该商品 ID 所在的位置,进而获取商品信息 。

八、总结

二分查找作为一种高效的查找算法,在 C++ 编程中占据着重要地位 。其基于分治策略,利用数组的有序性,通过不断将搜索区间减半,实现快速查找目标元素 ,时间复杂度低至 O (log n) ,空间复杂度为 O (1) ,在处理大规模数据时优势显著 。

在实现二分查找时,要掌握基本的代码框架,注意边界条件的处理、数据类型的选择以及防止整数溢出等问题 。同时,二分查找还有多种变体,如查找第一个等于给定值的元素、查找最后一个等于给定值的元素等,这些变体在不同的实际场景中有着广泛应用 。

从应用场景来看,二分查找不仅在有序数组和有序链表(改造后)等数据结构中发挥作用,在算法竞赛和日常编程中也大显身手 ,如解决搜索问题、最值问题,以及在数据库索引、查找配置文件等方面 。

对于读者而言,深入理解二分查找的原理和实现,能够提升编程思维和解决问题的能力 。在实际编程中,要根据具体需求灵活运用二分查找及其变体,不断优化程序性能 。希望本文能为大家在 C++ 二分查找的学习和应用中提供有益的参考,助力大家在编程道路上不断进步 。

相关文章:

C++ 二分查找:解锁高效搜索的密码

一、引言 在 C 编程的广阔领域中&#xff0c;数据处理和查找是日常开发中极为常见的操作。想象一下&#xff0c;你有一个包含数百万个数据的有序数组&#xff0c;需要从中快速找到特定的元素&#xff0c;如果采用逐个遍历的方式&#xff0c;效率之低可想而知&#xff0c;而二分…...

YOLO12改进-模块-引入Channel Reduction Attention (CRA)模块 降低模型复杂度,提升复杂场景下的目标定位与分类精度

在语义分割任务中&#xff0c;基于 Transformer 的解码器需要捕获全局上下文信息&#xff0c;但传统自注意力机制&#xff08;如 SRA&#xff09;因高分辨率特征图导致计算成本高昂。现有方法多通过降低空间分辨率减少计算量&#xff0c;但未充分优化通道维度。为平衡全局上下文…...

sparkSQL读入csv文件写入mysql

思路 示例 &#xff08;年龄>18改成>20) mysql的字符集问题 把user改成person “让字符集认识中文”...

如何确定自己的职业发展方向?

引言 确定职业发展方向是一个需要深度自我探索和外部信息结合的过程。以下是系统化的思考框架和行动步骤&#xff0c;帮助你逐步清晰方向&#xff1a; 一、核心问题&#xff1a;职业方向的本质是什么&#xff1f; 职业方向的核心是找到 “你能做什么”&#xff08;能力&…...

【LLIE专题】基于Retinex理论的transformer暗光增强

Retinexformer: One-stage Retinex-based Transformer for Low-light Image Enhancement&#xff08;2023&#xff0c;ICCV&#xff09; 专题介绍一、研究背景二、Retinexformer方法1. 通用Retinex理论2. 作者建立的Retinex理论3. ORF(one stage Retinex-based Framework)4. 网…...

C++多态与虚函数详解——从入门到精通

C多态与虚函数详解——从入门到精通 引言 在C面向对象编程中&#xff0c;多态是一个核心概念&#xff0c;它赋予了程序极大的灵活性和扩展性。本文将通过六个精心设计的实例&#xff0c;深入浅出地讲解C中的多态、虚函数、继承和抽象类等概念&#xff0c;帮助初学者快速理解这…...

自适应Prompt技术:让LLM精准理解用户意图的进阶策略

开发&#xff5c;界面&#xff5c;引擎&#xff5c;交付&#xff5c;副驾——重写全栈法则&#xff1a;AI原生的倍速造应用流 来自全栈程序员 nine 的探索与实践&#xff0c;持续迭代中。 欢迎关注评论私信交流~ 一、核心挑战&#xff1a;传统Prompt的局限性 传统静态Prompt&…...

Java文件读写程序

1.引言 在日常的软件开发中&#xff0c;文件操作是常见的功能之一。不仅要了解如何读写文件&#xff0c;更要知道如何安全地操作文件以避免程序崩溃或数据丢失。这篇文章将深入分析一个简单的 Java 文件读写程序 Top.java&#xff0c;包括其基本实现、潜在问题以及改进建议&am…...

数字电子技术基础(六十)——使用Digital软件绘制脉冲触发的触发器

目录 1 使用Digital软件来绘制脉冲触发的触发器 1.1 使用Digital软件来绘制脉冲触发的SR触发器 1.2 使用Digitial软件绘制脉冲触发的JK触发器 1.3 使用Digital软件绘制脉冲触发D触发器 1 使用Digital软件来绘制脉冲触发的触发器 1.1 使用Digital软件来绘制脉冲触发的SR触发…...

C++学习:六个月从基础到就业——C++20:范围(Ranges)基础

C学习&#xff1a;六个月从基础到就业——C20&#xff1a;范围(Ranges)基础 本文是我C学习之旅系列的第五十一篇技术文章&#xff0c;也是第三阶段"现代C特性"的第十三篇&#xff0c;介绍C20引入的范围(Ranges)库的基础知识。查看完整系列目录了解更多内容。 引言 S…...

【AGI】模型性能评估框架EvalScope

【AGI】模型性能评估框架EvalScope 项目地址&#xff1a;https://github.com/modelscope/evalscope ​ EvalScope 是由阿里巴巴魔搭社区&#xff08;ModelScope&#xff09;推出的一款开源模型评估框架&#xff0c;旨在为大语言模型&#xff08;LLM&#xff09;和多模态模型提供…...

【老马】离线版金融敏感信息加解密组件开源项目 encryption-local

前言 你是否存在这样的苦恼&#xff0c;数据需要安全存储&#xff0c;但是每个系统大家自己写&#xff0c;很浪费时间。。 每一个子项目各自为政&#xff0c;加解密搞得也无法统一。也许下面这个开源项目可以帮助你。 encryption-local 一个离线版本的金融敏感信息加解密工具…...

利用systemd启动部署在服务器上的web应用

0.背景 系统环境&#xff1a; Ubuntu 22.04 web应用情况&#xff1a; 前后端分类&#xff0c;前端采用react&#xff0c;后端采用fastapi 1.具体配置 1.1 前端配置 开发态运行&#xff08;启动命令是npm run dev&#xff09;,创建systemd服务文件 sudo nano /etc/systemd/…...

YOLOv5目标构建与损失计算

YOLOv5目标构建与损失计算 YOLOv5目标构建与损失计算构建目标关键步骤解析&#xff1a; 计算损失关键实现细节解析各损失分量说明 YOLOv5目标构建与损失计算 YOLOv5作为单阶段目标检测的经典算法&#xff0c;其高效的检测性能离不开精心设计的训练目标构建和损失计算策略。本文…...

【Linux】ELF与动静态库的“暗黑兵法”:程序是如何跑起来的?

目录 一、什么是库&#xff1f; 1. C标准库&#xff08;libc&#xff09; 2. C标准库&#xff08;libstdc&#xff09; 二、静态库 1. 静态库的生成 2. 静态库的使用 三、动态库 1. 动态库的生成 2. 动态库的使用 3. 库运行的搜索路径。 &#xff08;1&#xff09;原因…...

【图书管理系统】用户注册系统实现详解

引言 本系统允许用户输入用户名和密码&#xff0c;前端通过AJAX请求将数据发送到后端&#xff0c;后端验证并存储用户信息&#xff0c;同时为每个用户创建一个专属图书表。尽管这是一个基础实现&#xff0c;但它展示了前后端分离开发的核心思想。博客还将讨论潜在的优化点&…...

FastDFS分布式文件系统架构学习(一)

FastDFS分布式文件系统架构学习 1. FastDFS简介 FastDFS是一个开源的轻量级分布式文件系统&#xff0c;由淘宝资深架构师余庆设计并开发。它专为互联网应用量身定制&#xff0c;特别适合以中小文件&#xff08;如图片、文档、音视频等&#xff09;为载体的在线服务。FastDFS不…...

Oracle 内存优化

Oracle 的内存可以按照共享和私有的角度分为系统全局区和进程全局区&#xff0c;也就是 SGA和 PGA(process global area or private global area)。对于 SGA 区域内的内存来说&#xff0c;是共享的全局的。在 UNIX 上&#xff0c;必须为 Oracle 设置共享内存段(可以是一个或者多…...

算法题(149):矩阵消除游戏

审题&#xff1a; 本题需要我们找到消除矩阵行与列后可以获得的最大权值 思路&#xff1a; 方法一&#xff1a;贪心二进制枚举 这里的矩阵消除时&#xff0c;行与列的消除会互相影响&#xff0c;所以如果我们先统计所有行和列的总和&#xff0c;然后选择消除最大的那一行/列&am…...

AI:NLP 情感分析

💬 从零开始掌握情感分析:NLP 初学者实战指南 本文适合自然语言处理(NLP)入门者,聚焦于最热门应用之一——情感分析(Sentiment Analysis)。无论你是学生、工程师,还是数据爱好者,都可以通过本文了解情感分析的原理、方法和实现技巧。 🧠 一、什么是情感分析? 情感…...

LearnOpenGL---着色器

着色器的例子 文章目录 着色器的例子1.颜色变化的三角形2.构造三个顶点颜色不同的一个三角形 1.颜色变化的三角形 #include <glad/glad.h> #include <GLFW/glfw3.h>#include <iostream> #include <cmath>void framebuffer_size_callback(GLFWwindow* …...

计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 13.几何着色器(一)修改顶点

几何着色器 以下是OpenGL图像管线的主要阶段&#xff1a; 几何着色器&#xff08;Geometry Shader&#xff09; 几何着色器是OpenGL管线中的一个可选阶段&#xff0c;位于顶点着色器和片段着色器之间。它能够动态地生成或修改图元&#xff08;primitives&#xff09;。 主…...

如何利用 Java 爬虫获得某书笔记详情:实战指南

在知识分享和学习的领域&#xff0c;许多平台提供了丰富的书籍笔记和学习资源。通过 Java 爬虫技术&#xff0c;我们可以高效地获取这些笔记的详细信息&#xff0c;以便进行进一步的分析和整理。本文将详细介绍如何利用 Java 爬虫获取某书笔记详情&#xff0c;并提供完整的代码…...

【关联git本地仓库,上传项目到github】

目录 1.下载git2.绑定用户3.git本地与远程仓库交互4.github项目创建5.上传本地项目到github6.完结撒花❀❀❀&#xff01;&#xff01;&#xff01; 1.下载git git下载地址&#xff1a;https://git-scm.com/downloads 下载安装后创建快捷地址&#xff1a;&#xff08;此处比较…...

计算机科技笔记: 容错计算机设计05 n模冗余系统 TMR 三模冗余系统

NMR&#xff08;N-Modular Redundancy&#xff0c;N 模冗余&#xff09;是一种通用的容错设计架构&#xff0c;通过引入 N 个冗余模块&#xff08;N ≥ 3 且为奇数&#xff09;&#xff0c;并采用多数投票机制&#xff0c;来提升系统的容错能力与可靠性。单个模块如果可靠性小于…...

配置代理服务器访问github、google

配置代理服务器访问github、google 背景与原理配置环境配置步骤云主机配置Windows客户端创建SSH隧道安装 Windows 内置 OpenSSHssh config 配置文件创建动态代理隧道 浏览器代理设置 验证浏览器访问google、githubssh 访问github 背景与原理 由于网络政策限制&#xff0c;中国…...

Java API学习笔记

一.类 1. String 类 不可变性&#xff1a;String对象创建后不可修改&#xff0c;每次操作返回新对象 String str "Hello"; str.length(); str.charAt(0); str.substring(1, 4); str.indexOf("l"); str.equals("hel…...

C++ map容器: 插入操作

1. map插入操作基础 map是C STL中的关联容器&#xff0c;存储键值对(key-value pairs)。插入元素时有四种主要方式&#xff0c;各有特点&#xff1a; 1.1 头文件与声明 #include <map> using namespace std;map<int, string> mapStu; // 键为int&#xff0c;值…...

Linux SSH 远程连接全攻略:从加密原理到实战配置(含图解)

一、SSH 加密体系核心理论 &#xff08;一&#xff09;对称加密与非对称加密对比解析 1. 加密算法分类与应用场景 类型代表算法密钥数量加密速度安全性特点典型用途对称加密AES、3DES1 个★★★★☆密钥传输风险高会话数据加密非对称加密RSA、ECC2 个★★☆☆☆公钥可公开&a…...

项目制作流程

一、使用 CRA 创建项目 npx create-react-app name 二、按照业务规范整理项目目录 &#xff08;重点src目录&#xff09; 三、安装插件 npm install sass -Dnpm install antd --savenpm install react-router-dom 四、配置基础路由 Router 1. 安装路由包 react-router-dom …...

ctr查看镜像

# 拉取镜像到 k8s.io 命名空间 sudo nerdctl --namespace k8s.io pull nginx:1.23.4 # 验证镜像是否已下载 sudo nerdctl --namespace k8s.io images 下载镜像到k8s.io名称空间下 nerdctl --namespace k8s.io pull zookeeper:3.6.2 sudo ctr image pull --namespace k8s.io …...

【深度学习基础】从感知机到多层神经网络:模型原理、结构与计算过程全解析

【深度学习基础】从感知机到多层神经网络&#xff1a;模型原理、结构与计算过程全解析 1. 引言 神经网络的重要性&#xff1a; 作为人工智能的核心技术之一&#xff0c;神经网络通过模拟人脑神经元的工作机制&#xff0c;成为解决复杂模式识别、预测和决策任务的利器。从图像分…...

discuz X3.5批量新建用户

<?php define(IN_DISCUZ, true); require ./source/class/class_core.php; // 确保管理员权限&#xff08;可选&#xff0c;增加安全性&#xff09;删除这一段加粗则可以直接使用. if ($_G[adminid] ! 1) { exit(Access denied. Only admin allowed.); } C::app()->…...

symfonos: 1靶场

symfonos: 1 来自 <https://www.vulnhub.com/entry/symfonos-1,322/> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182&#xff0c;靶场IP192.168.23.252 3&…...

C# String 格式说明符

标准格式说明符数字格式说明符C 或 c&#xff1a;货币格式D 或 d&#xff1a;十进制数字格式E 或 e&#xff1a;科学计数法格式。F 或 f&#xff1a;固定点格式G 或 g&#xff1a;常规格式N 或 n&#xff1a;数字格式P 或 p&#xff1a;百分比格式X 或 x&#xff1a;十六进制格…...

Python高级特性深度解析:从熟练到精通的跃迁之路

Python高级特性深度解析&#xff1a;从熟练到精通的跃迁之路 引言 对于已经掌握Python基础语法的开发者而言&#xff0c;如何突破瓶颈进入高手行列&#xff1f;本文将从Python的高级特性入手&#xff0c;深入剖析那些能让代码更优雅、效率更高的技术点&#xff0c;助你完成从…...

【微信小程序 + 高德地图API 】键入关键字搜索地址,获取经纬度等

前言 又到熟悉的前言&#xff0c;接到个需求&#xff0c;要引入高德地图api&#xff0c;我就记录一下&#xff0c;要是有帮助记得点赞、收藏、关注&#x1f601;。 后续有时间会慢慢完善一些文章&#xff1a;&#xff08;画饼时间&#xff09; map组件自定义气泡、mark标记点…...

贪心、分治和回溯算法

1. 贪心算法 1.1. 贪心算法的概念 定义&#xff1a;在求解过程中&#xff0c;始终做出当前状态下看起来“最优”的选择&#xff0c;不回退。核心思想&#xff1a;每一步都选择当前最优解&#xff0c;期望最后得到全局最优解。 适用问题的特征&#xff1a; 问题可以分解成多个…...

window自带截图快捷键

Win Shift S&#xff1a;按此组合键后&#xff0c;会出现截图模式选择框&#xff0c;可选择矩形截图、任意形状截图、窗口截图和全屏幕截图&#xff0c;然后使用 “Ctrl V” 粘贴截图内容...

简单使用Slidev和PPTist

简单使用Slidev和PPTist 1 简介 前端PPT制作有很多优秀的工具包&#xff0c;例如&#xff1a;Slidev、revealjs、PPTist等&#xff0c;Slidev对Markdown格式支持较好&#xff0c;适合与大模型结合使用&#xff0c;选哟二次封装&#xff1b;revealjs适合做数据切换&#xff0c…...

1.2.2

某智慧养老平台的心率监测模块目前存在数据准确性不高、异常预警响应慢等问题&#xff0c;影响了老年人健康监测的体验和服务质量。作为人工智能训练师&#xff0c;你需要结合业务知识和人工智能技术&#xff0c;对该模块进行优化设计与实现。 &#xff08;1&#xff09;列出心…...

LeeCode 101.对称二叉树

给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 提示&#xff1a; 树中节点数目在范围 [1, 1000] 内-100 < Node.val < 100 进阶&#xff1a;你可以运用递归和迭代两种方法解决这个问题吗&#xff1f; 答案 && 测试代码&#xff1a; #include &…...

面向GIS的Android studio移动开发(二)--在地图上绘制电子围栏

电子围栏&#xff0c;校园跑的常客&#xff0c;也是定位打卡必不可少的东西 主要代码&#xff1a; 创建电子围栏代码 // 添加多边形地理围栏&#xff08;兼容2023版SDK&#xff09;private void addPolygon(String fenceName, List<LatLng> points) {if (points null…...

《从零开始:Spring Cloud Eureka 配置与服务注册全流程》​

关于Eureka的学习&#xff0c;主要学习如何搭建Eureka&#xff0c;将order-service和product-service都注册到Eureka。 1.为什么使用Eureka? 我在实现一个查询订单功能时&#xff0c;希望可以根据订单中productId去获取对应商品的详细信息&#xff0c;但是产品服务和订单服…...

能力验证及大练兵活动第一期

计算机 请根据计算机检材&#xff0c;回答以下问题&#xff1a; (10道题&#xff0c;共19.0分) 1. 计算机中曾挂载的Bitlocker加密分区的恢复密钥后6位为&#xff1f;&#xff08;答案格式&#xff1a;6位数字&#xff09; (1.0分) 答案&#xff1a;700755 2. 请写出曾远程连…...

TASK03【Datawhale 组队学习】搭建向量知识库

文章目录 向量及向量知识库词向量与向量向量数据库 数据处理数据清洗文档分割 搭建并使用向量数据库 向量及向量知识库 词向量与向量 词向量&#xff08;word embedding&#xff09;是一种以单词为单位将每个单词转化为实数向量的技术。词向量背后的主要想理念是相似或相关的…...

ProfibusDP转ModbusRTU的实用攻略

ProfibusDP转ModbusRTU的实用攻略 在工业自动化领域中&#xff0c;Profibus DP和Modbus RTU是两种常见的通信协议。 Profibus DP是一种广泛应用于过程控制和工厂自动化的现场总线标准&#xff0c;具有高实时性和可靠性。 而Modbus RTU则是一种串行通信协议&#xff0c;常用于…...

基于开源AI智能名片链动2+1模式S2B2C商城小程序源码的去中心化商业扩散研究

摘要&#xff1a;本文探讨在去中心化商业趋势下&#xff0c;开源AI智能名片链动21模式S2B2C商城小程序源码如何助力企业挖掘数据价值、打破信息孤岛&#xff0c;实现商业高效扩散。通过分析该技术组合的架构与功能&#xff0c;结合实际案例&#xff0c;揭示其在用户关系拓展、流…...

iOS 工厂模式

iOS 工厂模式 文章目录 iOS 工厂模式前言工厂模式简单工厂案例场景分析苹果类优点缺点 小结 工厂模式客户端调用**优点****缺点** 抽象工厂模式三个模式对比 前言 笔者之前学习了有关于设计模式的六大原则,之前简单了解过这个工厂模式,今天主要是重新学习一下这个模式,正式系统…...

LaTeX OCR - 数学公式识别系统

文章目录 一、关于 LaTeX OCR1、项目概览架构图2、相关链接资源3、功能特性 二、安装配置基础环境要求Linux 安装Mac 安装 三、使用指南1、快速训练&#xff08;小数据集&#xff09;2、完整训练&#xff08;大数据集&#xff09; 四、可视化功能训练过程可视化预测过程可视化 …...