排序学习整理(2)
上集回顾
排序学习整理(1)-CSDN博客
2.3 交换排序
交换排序的基本思想是:根据序列中两个记录键值的比较结果,交换这两个记录在序列中的位置。
特点:
- 通过比较和交换操作,将键值较大的记录逐步移动到序列的尾部,而键值较小的记录逐步移动到序列的前部。
- 重复此过程,直到整个序列变得有序。
2.3.1 冒泡排序
冒泡排序(Bubble Sort)是一种简单的交换排序算法,其核心思想是通过重复的比较和交换操作,将序列中的最大值或最小值逐步“冒泡”到序列的尾部或头部。
基本思想
从序列的起始位置开始,依次比较相邻的两个元素:
如果它们的顺序不正确(如升序时前一个大于后一个),则交换它们的位置。
一轮比较后,当前未排序部分的最大值会被“冒泡”到末尾。
对剩下的未排序部分重复上述过程,直到整个序列有序。
算法步骤
- 初始化一个外层循环,用来控制需要比较的轮数。
- 在每轮循环中,从序列的开头开始,逐一比较相邻的两个元素,完成交换。
- 每轮排序结束后,未排序部分的长度减1。
- 重复上述操作,直到不需要再比较。
代码实现
void BubbleSort(int* arr, int n) {for (int i = 0; i < n - 1; i++) { // 控制排序轮数int swapped = 0; // 标记本轮是否发生交换for (int j = 0; j < n - 1 - i; j++) { // 控制每轮比较次数if (arr[j] > arr[j + 1]) { // 如果顺序不正确int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;swapped = 1; // 标记发生了交换}}if (!swapped) { // 如果本轮没有交换,说明已经有序break;}}
}
特性总结
算法复杂度
- 时间复杂度:
- 最好情况(序列已排序):O(n)
- 最坏情况(序列逆序):O(n^2)
- 平均情况:O(n^2)
- 空间复杂度:只需要常数级额外空间,空间复杂度为 O(1)。
- 稳定性:冒泡排序是稳定的排序算法,因为在比较相等元素时,它不会改变它们的相对位置。
优缺点和适用场景就不介绍了,冒泡的效率太过于低下,基本只用于教学了
2.3.2 快速排序
基本思想是:从待排序序列中随机选取一个元素作为基准值,依据该基准值将序列划分为两个子序列,其中左子序列的所有元素都小于基准值,右子序列的所有元素都大于基准值。然后对左右子序列分别重复这一过程,直到所有元素都排列到正确的位置上为止。
快速排序实现的主框架
//快速排序
void QuickSort(int* a, int left, int right){if (left >= right) {return;}//_QuickSort⽤于按照基准值将区间[left,right)中的元素进⾏划分int meet = _QuickSort(a, left, right);QuickSort(a, left, meet - 1);QuickSort(a, meet + 1, right);
}
主要有以下几种实现方法:
2.3.2.1 hoare版本
Hoare版本的快速排序是由算法提出者Tony Hoare在1962年设计的一种经典快速排序实现。该版本利用分区的思想,将数组分成两部分,使得一部分元素小于基准值,另一部分元素大于基准值。随后对两部分递归地应用快速排序,直到数组有序。
基本思想
核心操作是“分区”,使用左右指针分别从两端向中间扫描,找到需要交换的元素位置,最终将数组划分为左右两部分。
-
Hoare版本的快速排序通过分区的思想,将数组分成两部分:
- 左子数组中的元素均小于等于基准值。
- 右子数组中的元素均大于等于基准值。 采用递归或迭代方式,对子数组继续进行快速排序,直到子数组长度为1或0,排序完成。
算法步骤
- 选择基准值: 通常选择当前子数组的第一个元素作为基准值。
- 分区:
- 设置左右两个指针,分别指向当前子数组的两端。
- 右指针向左移动,找到第一个小于等于基准值的元素。
- 左指针向右移动,找到第一个大于等于基准值的元素。
- 如果左右指针未交错,交换两指针指向的元素,继续移动指针。
- 当左右指针交错时,分区完成,并返回分界点。
- 递归排序:
- 将数组按照分界点划分为左右两部分。
- 分别对左右部分递归执行上述过程,直到子数组长度为1或0。
问题1:为什么跳出循环后right位置的值⼀定不大于key?
当 left > right 时,右指针(right)已经移动到了左指针(left)的左侧。由于在分区过程中,左指针从左到右扫描的所有数据均不大于基准值(key),因此,跳出循环时,右指针(right)所指向的数据一定不大于基准值(key)。
问题2:为什么left 和 right指定的数据和key值相等时也要交换?
相等的值参与交换确实有一些额外消耗,但在实际中,数组可能存在大量重复元素,如果相等的值不参与交换,可能导致分区无法有效进行,从而影响排序的正确性和效率。
代码实现
// 交换函数
void Swap(int* p1, int* p2) {int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
// 快速排序
void QuickSort(int* a, int left, int right) {if (left >= right) { // 递归边界条件:区间只有一个元素或无元素return;}int begin = left, end = right; // 记录当前区间int keyi = left; // 基准值初始为第一个元素的下标while (left < right) {// 从右向左寻找比基准值小的元素while (a[right] >= a[keyi] && left < right) {right--;}// 从左向右寻找比基准值大的元素while (a[left] <= a[keyi] && left < right) {left++;}// 交换左右指针指向的值Swap(&a[left], &a[right]);}// 基准值归位Swap(&a[left], &a[keyi]);keyi = left; // 更新基准值位置// 对左右两部分递归排序QuickSort(a, begin, keyi - 1); // 左部分QuickSort(a, keyi + 1, end); // 右部分
}
特性总结
算法复杂度
时间复杂度:
最好情况:O(n logn),每次分区都能平均划分为两半。
最坏情况:O(n^2),当基准值总是选择到最小或最大值时,分区极不均衡。
平均情况:O(n logn),这是快速排序的典型表现。
空间复杂度:
O(logn):递归调用栈的深度。
优缺点
优点:
- 时间复杂度低:平均性能优于大多数排序算法,适合大规模数据。
- 原地排序:不需要额外的内存(仅递归栈空间)。
- 实现简单:通过分区逻辑实现高效的递归。
缺点:
- 不稳定:相同元素的相对顺序可能改变。
- 最坏情况效率低:对于完全有序或接近有序的数据,性能可能退化为O(n^2)。
- 递归调用栈问题:当数据规模过大时,递归调用深度可能导致栈溢出。
适用场景
- 大规模数据排序:快速排序在大数据场景下表现良好。
- 对稳定性无要求的场景:例如数字或字符排序。
- 通用排序需求:适合随机分布的无序数据集。
很明显的缺点不少,接下来介绍针对不同情况优化的另外三种快排
2.3.2.2 挖坑法
挖坑法(也称为坑填法或坑填交换法)是一种在排序算法中常用的技巧,特别是在快速排序和堆排序等算法的实现中。常用于处理两个元素交换问题,并且通常配合双指针或者分区操作来完成排序。
挖坑法在大量重复元素的情况下能减少交换次数,因此在这些场景下的优化效果明显。
基本思想
在元素交换过程中使用一个临时“坑”来存储一个元素的值,避免出现直接交换时元素覆盖的情况。这使得元素能够顺利地放到正确的位置,并且交换过程更加高效。
在快速排序的分区操作中,使用两个指针分别从两端扫描,遇到需要交换的元素时,利用“坑”存储其中一个元素,等另一个元素找到合适位置后再进行交换。最终基准值会被放置到“坑”中,实现正确的分区。
算法步骤
- 选择基准值:选择一个元素作为基准值(通常是第一个元素,或随机选择一个)。
- 左右指针扫描:
右指针从右侧开始,向左扫描,找到一个小于等于基准值的元素。
左指针从左侧开始,向右扫描,找到一个大于等于基准值的元素。
- 交换元素:
如果左指针和右指针没有交错,就交换这两个元素。
交换时,使用一个临时“坑”来存放其中一个元素的值,避免覆盖问题。
- 继续扫描:重复步骤2和步骤3,直到左右指针交错。
- 放置基准值:当左右指针交错时,将基准值放入当前“坑”位置,即完成分区。
- 递归排序:对左右两部分继续递归执行快速排序。
代码实现
void QuickSort(int* a, int left, int right) {if (left >= right) {return; // 当区间为空或只有一个元素时,递归结束}int begin = left;int end = right;int keyi = a[left]; // 基准值while (left < right) {// 从右向左寻找比基准值小的数while (a[right] >= keyi && left < right) {right--;}if (left < right) {a[left] = a[right]; // 填坑}// 从左向右寻找比基准值大的数while (a[left] <= keyi && left < right) {left++;}if (left < right) {a[right] = a[left]; // 填坑}}// 最后将基准值填入当前坑位a[left] = keyi;// 对左右区间递归排序QuickSort(a, begin, left - 1); // 左区间QuickSort(a, left + 1, end); // 右区间
}
复杂度优缺点什么的和hoare版差不多,就介绍下与hoare法相对的优化情况吧
减少了交换次数:Hoare法在某些情况下需要交换多个位置,尤其是当扫描到不满足条件的元素时。挖坑法则通过填坑和直接交换,使得不需要频繁交换,进一步提升了效率。
保持数据的稳定性:挖坑法对于数据的处理方式相对较为稳定,避免了一些冗余的交换,且能够使得算法执行过程中更有序。
提高了数据的分区效果:挖坑法有助于实现更平衡的分区,尤其是在遇到重复元素或者大范围的相同值时,能够更均匀地进行分割。由于它通过“填坑”的方式保持了分区的连续性,因此在数据比较“均匀”的情况下能够带来较好的分割效果。
2.3.2.3 前后指针法
前后指针法(Two-pointer technique)是一种常用的技术,通常用于排序算法中的分区操作,特别是在快速排序的分区阶段。它通过设置两个指针从数组的两端向中间扫描,逐步找到需要交换的位置,从而实现分区操作。
前后指针法对于提高交换效率和减少不必要的交换有很大帮助,尤其是在数据量大且分布不均匀时
基本思想
- 使用两个指针,一个从数组的左端开始(前指针),另一个从数组的右端开始(后指针)。
- 前指针向右扫描,直到找到一个大于等于基准值的元素;后指针向左扫描,直到找到一个小于等于基准值的元素。
- 当前指针小于后指针时,交换这两个元素。交换后,继续移动两个指针,直到指针交错或相遇。
- 当指针交错时,结束扫描,将基准值放到指针交错的位置,完成分区。
算法步骤
- 选择基准值:选择一个基准值,通常选择数组的第一个元素或者最后一个元素。
- 初始化指针:设置两个指针,前指针(
left
)指向数组的起始位置,后指针(right
)指向数组的结束位置。 - 扫描交换:
- 前指针:从左向右扫描,找到第一个大于等于基准值的元素。
- 后指针:从右向左扫描,找到第一个小于等于基准值的元素。
- 如果前指针小于后指针,则交换这两个元素,继续扫描。
- 基准值放置:当指针交错或相遇时,将基准值放入指针交错的位置,实现分区。
- 递归排序:对左侧和右侧子数组进行递归排序。
代码实现
Swap函数和上面的一样,就不再水一次了
void QuickSort(int* a, int left, int right) {// 如果区间无效或只剩一个元素,直接返回if (left >= right) {return;}// 设置初始基准值的位置(选取左边的元素作为基准值)int prev = left; // prev 用于标记小于基准值的区域的末尾位置int cur = prev + 1; // cur 用于遍历数组int pivotIndex = left; // 基准值的位置(初始化为左边界)// 遍历整个区间,进行分区while (cur <= right) {// 如果当前元素小于基准值并且 prev 位置还没有与 cur 交换if (a[cur] < a[pivotIndex] && ++prev != cur) {// 如果符合条件,则交换 a[prev] 和 a[cur]Swap(&a[prev], &a[cur]);}++cur; // 继续向右移动 cur 指针}// 最后将基准值与 prev 位置的元素交换,将基准值放到正确的位置Swap(&a[prev], &a[pivotIndex]);pivotIndex = prev; // 更新基准值位置// 递归处理左右两个子区间QuickSort(a, left, pivotIndex - 1); // 处理左区间QuickSort(a, pivotIndex + 1, right); // 处理右区间
}
算法复杂度和优缺点一样继续与hoare同,优化在于
减少了交换次数:在Hoare法中,当左右指针扫描时,可能会在每次比较时都进行交换。而前后指针法则是只在需要时才交换,并且扫描过程是从两端开始的,能够更高效地找到合适的交换元素。
提高了分区效率:前后指针法可以确保左右指针每次都能找到需要交换的元素,因此比传统的Hoare法可能更快地将数据分割为两部分。这种方法避免了多个不必要的交换,提高了分区的速度。
优化情况:当数据的顺序比较混乱,或者大部分元素都较接近基准值时,前后指针法能够更有效地进行数据分割,减少了不必要的比较和交换操作。
2.3.2.4 非递归版本
饺子醋来咯,尝试尽量讲清楚
首先,这个版本需要栈来实现,学了栈再来,先上官方一点的介绍
传统的快速排序算法通常使用递归来实现分区和排序操作,但在某些情况下(例如,当递归深度过大时,可能导致栈溢出),可以使用非递归版的快速排序来避免递归带来的开销。非递归版快速排序使用显式的栈来模拟递归的调用,借助栈保存子数组的边界,逐步进行分区和排序。
非递归版则主要解决了递归带来的栈溢出问题,适合处理大规模数据或栈空间受限的情况,但对于排序速度并没有显著提高。
基本思想
非递归版快速排序的基本思想是:
- 使用栈代替递归的调用栈,通过显式地维护子数组的起始和结束位置。
- 每次分区操作后,将新的左右子数组的边界压入栈中,继续分区,直到栈为空。
- 由于栈模拟了递归过程,因此在内存方面比传统递归方法更加高效。
算法步骤
- 初始化栈:初始化一个栈,用来存储子数组的左右边界。
- 压入初始边界:将整个数组的左右边界压入栈中(即初始的低位和高位)。
- 分区操作:
- 从栈中弹出一个子数组的边界(即子数组的左端点和右端点)。
- 对该子数组进行分区操作,将其分为两个部分,基准值将放在正确位置。
- 压入子数组的边界:根据分区结果,将两个子数组的边界压入栈中,继续分区。
- 循环直到栈为空:重复上述步骤,直到栈为空,即所有子数组都被处理完。
其实就记住这个操作就好了,取栈顶区间,单趟排序,右左子区间入栈,不断重复及完成了整个函数。
代码实现
void QuickSortNonR(int* a, int left, int right) {ST st;STInit(&st); // 初始化栈STPush(&st, right); // 将右边界入栈STPush(&st, left); // 将左边界入栈// 循环栈中的区间进行排序while (!STEmpty(&st)) {int begin = STTop(&st); // 获取当前区间的左边界STPop(&st); // 弹出左边界int end = STTop(&st); // 获取当前区间的右边界STPop(&st); // 弹出右边界int keyi = begin; // 选择基准元素的初始位置int cur = begin + 1; // 当前元素指针int prev = begin; // 上一个小于基准元素的位置// 对区间内的元素进行排序while (cur <= end) {if (a[cur] < a[keyi] && ++prev != cur) // 如果当前元素小于基准元素,则交换Swap(&a[prev], &a[cur]);++cur;}// 将基准元素放到正确的位置Swap(&a[keyi], &a[prev]);keyi = prev; // 更新基准元素位置// 如果基准元素右边还有元素,继续排序右边区间if (keyi + 1 < end) {STPush(&st, end);STPush(&st, keyi + 1);}// 如果基准元素左边还有元素,继续排序左边区间if (keyi - 1 > begin) {STPush(&st, keyi - 1);STPush(&st, begin);}}STDestroy(&st); // 销毁栈
}
栈实现的代码拿的是自己上次的栈的实现(基础)-CSDN博客
特性总结
算法复杂度
时间复杂度不变,空间复杂度正常也是 O(logn),但在最坏情况(有序或接近有序)会到O(n)
优缺点
优点:
- 避免栈溢出:非递归版的快速排序通过显式的栈来模拟递归,避免了因递归深度过大而导致栈溢出的风险。
- 节省栈空间:在递归方法中,栈的空间随着递归深度的增加而增加,而非递归版的快速排序通过显式栈管理,节省了递归栈空间。
缺点:
- 代码复杂度增加:非递归版的快速排序实现需要额外的栈结构来模拟递归,增加了代码的复杂性。
- 空间开销:尽管非递归版避免了递归栈的开销,但仍然需要额外的栈空间来存储子数组的边界,尤其对于大数组时,空间开销可能较大。
适用场景
- 递归深度较大时:当数据集非常大或递归深度较深时,非递归版快速排序通过避免栈溢出,使得排序过程更稳定。
- 内存限制:如果系统的栈空间有限,递归深度可能会导致栈溢出,此时非递归版更为适用。
- 需要改进性能的应用场景:对于一些对性能要求较高的应用,避免递归栈开销可能会带来一定的性能提升。
2.3.2.5 优化方法
2.3.2.5.1 三数取中
这个方法针对前面4种都不利的有序数组,从这个角度出发,我们有了三数取中的优化方式:
即选出mid=(left+right)/2
a[left]、a[right]、a[mid]这三个数中,值为中位数的那个数,然后将它于a[keyi]交换。
下面代码基于前后指针法
// 三数取中法
int GetMidi(int* a, int begin, int end) {// 计算中间元素的索引int mid = begin + ((end - begin) >> 1);// 判断mid元素是否在begin和end之间(即a[mid] 是位于 [a[begin], a[end]] 之间)if ((a[mid] >= a[begin] && a[mid] <= a[end]) || (a[mid] >= a[end] && a[mid] <= a[begin])) {return mid; // 如果mid符合条件,返回mid的索引}// 如果a[begin]比a[mid]大,且a[begin]比a[end]小,或者a[begin]比a[mid]小,且a[begin]比a[end]大if ((a[begin] <= a[mid] && a[begin] >= a[end]) ||(a[begin] >= a[mid] && a[begin] <= a[end])) {return begin; // 返回begin的索引}// 默认返回end的索引return end;
}// 快速排序主函数
int QuickSort(int* a, int begin, int end) {// 三数取中法优化:选择begin, mid, end三个元素的中位数作为基准元素int ki = GetMidi(a, begin, end); // 获取中位数元素的索引Swap(&a[begin], &a[ki]); // 将中位数元素与begin位置的元素交换int keyi = begin; // keyi是基准元素的初始位置int prev = begin; // prev是扫描过程中已排序元素的最右边的位置int next = begin + 1; // next是当前扫描到的元素位置// 前后指针法进行分区操作while (next <= end) {// 如果当前元素小于基准元素,交换到prev位置,并更新prev的位置if (a[next] < a[keyi] && ++prev != next) {Swap(&a[prev], &a[next]);}next++; // 移动next指针,扫描下一个元素}// 将基准元素放到正确的位置(即prev位置),并返回基准元素的位置Swap(&a[keyi], &a[prev]);return prev; // 返回基准元素的最终位置
}
注释这么详细就不用额外介绍了吧(
来下一个优化
2.3.2.5.2 小区间优化
当区间很小时,直接采用插入排序,就不用继续递归了。
void QuickSort(int* a, int left, int right)
{// 如果区间内的元素只有一个或没有,直接返回,因为已经是最小子问题(即已经排好序)if (left >= right)return;// 对于小区间(小于10个元素),使用插入排序,可以减少递归深度,提高效率if (right - left + 1 < 10){InsertSort(a + left, right - left + 1); // 对[a+left, right]区间的元素进行插入排序}else{int begin = left, end = right;int midi = GetMidi(a, left, right); // 获取三数取中的基准索引Swap(&a[left], &a[midi]); // 将基准元素交换到left位置// 定义keyi为基准元素的索引,进行分区操作int keyi = left;// 进行前后指针法分区while (left < right){// 从右边开始,找一个小于基准的元素while (left < right && a[right] >= a[keyi]){--right; // right指针向左移动}// 从左边开始,找一个大于基准的元素while (left < right && a[left] <= a[keyi]){++left; // left指针向右移动}// 找到符合条件的元素后交换Swap(&a[left], &a[right]);}// 将基准元素放到正确的位置(即left位置),完成分区Swap(&a[left], &a[keyi]);keyi = left;// 递归调用对左右子数组进行排序QuickSort1(a, begin, keyi - 1); // 对左子数组进行排序QuickSort1(a, keyi + 1, end); // 对右子数组进行排序}
}
下一篇就讲归并排序和非比较排序吧,估计不长了
相关文章:
排序学习整理(2)
上集回顾 排序学习整理(1)-CSDN博客 2.3 交换排序 交换排序的基本思想是:根据序列中两个记录键值的比较结果,交换这两个记录在序列中的位置。 特点: 通过比较和交换操作,将键值较大的记录逐步移动到序列…...
AI蛋白质设计与人工智能药物设计
AI蛋白质设计与人工智能药物设计 AI蛋白质设计 一、蛋白质相关的深度学习简介 1.基础概念 1.1.机器学习简介:从手写数字识别到大语言模型 1.2.蛋白质结构预测与设计回顾 1.3.Linux简介 1.4.代码环境:VS code和Jupyter notebook* 1.5.Python关键概…...
IOS ARKit进行图像识别
先讲一下基础控涧,资源的话可以留言,抽空我把它传到GitHub上,这里没写收积分,竟然充值才能下载,我下载也要充值,牛! ARSCNView 可以理解画布或者场景 1 配置 ARWorldTrackingConfiguration AR追…...
初级数据结构——二叉搜索树
目录 前言一、定义二、基本操作三、时间复杂度分析四、变体五、动态图解六、代码模版七、经典例题[1.——700. 二叉搜索树中的搜索](https://leetcode.cn/problems/search-in-a-binary-search-tree/)代码题解 [2.——938. 二叉搜索树的范围和](https://leetcode.cn/problems/ra…...
C++设计模式之组合模式中如何实现同一层部件的有序性
在组合模式中,为了实现同一层上部件的有序性,可以采取以下几种设计方法: 1. 使用有序集合 使用有序集合(如 std::list、std::vector 或其他有序容器)来存储和管理子部件。这种方法可以确保子部件按照特定顺序排列&am…...
duxapp RN 端使用AppUpgrade 进行版本更新
版本更新包含了组件和工具的组合 注册 下面这是 duxcms 入口文件检查更新的注册方法,注册的同时会检查更新 import {request,updateApp,userConfig } from ./utils// 检查app更新 setTimeout(async () > {if (process.env.TARO_ENV rn) {// eslint-disable-n…...
【计网】自定义序列化反序列化(三) —— 实现网络版计算器【下】
🌎实现网络版计算器【下】 本次序列化与反序列化所用到的代码,Tcp服务自定义序列化反序列化实现网络版计算器。 文章目录: 实实现网络版计算器【下】 客户端实现 基于守护进程的改写 🚀客户端实现 在这之前,…...
神经网络中的优化方法(一)
目录 摘要Abstract1. 与纯优化的区别1.1 经验风险最小化1.2 代理损失函数1.3 批量算法和小批量算法 2. 神经网络中优化的挑战2.1 病态2.2 局部极小值2.3 高原、鞍点和其他平坦区域2.4 悬崖和梯度爆炸2.5 长期依赖2.6 非精确梯度2.7 局部和全局结构间的弱对应 3. 基本算法3.1 随…...
Linux 计算机网络基础概念
目录 0.前言 1.计算机网络背景 1.1 独立模式 1.2 网络互联 1.3 局域网(Local Area Network,LAN) 1.4 广域网(Wide Area Network,WAN) 2.协议 2.1什么是协议 2.2协议分层和软件分层 2.3 OSI七层网络模型 2.3…...
qt QGraphicsEllipseItem详解
1、概述 QGraphicsEllipseItem是Qt框架中QGraphicsItem的一个子类,它提供了一个可以添加到QGraphicsScene中的椭圆项。QGraphicsEllipseItem表示一个带有填充和轮廓的椭圆,也可以用于表示椭圆段(通过startAngle()和spanAngle()方法ÿ…...
Python websocket
router.websocket(/chat/{flow_id}) 接口代码,并了解其工作流程、涉及的组件以及如何基于此实现你的新 WebSocket 接口。以下内容将分为几个部分进行讲解: 接口整体概述代码逐行解析关键组件和依赖关系如何基于此实现新功能示例:创建一个新的…...
【MySQL-5】MySQL的内置函数
目录 1. 整体学习的思维导图 2. 日期函数 编辑 2.1 current_date() 2.2 current_time() 2.3 current_timestamp() 2.4 date(datetime) 2.5 now() 2.6 date_add() 2.7 date_sub() 2.8 datediff() 2.9 案例 2.9.1 创建一个出生日期登记簿 2.9.2 创建一个留言版 3…...
深度学习笔记之BERT(三)RoBERTa
深度学习笔记之RoBERTa 引言回顾:BERT的预训练策略RoBERTa训练过程分析静态掩码与动态掩码的比较模型输入模式与下一句预测使用大批量进行训练使用Byte-pair Encoding作为子词词元化算法更大的数据集和更多的训练步骤 RoBERTa配置 引言 本节将介绍一种基于 BERT \t…...
C++知识点总结(59):背包型动态规划
背包型动态规划 一、背包 dp1. 01 背包(限量)2. 完全背包(不限量)3. 口诀 二、例题1. 和是质数的子集数2. 黄金的太阳3. 负数子集和4. NASA的⻝物计划 一、背包 dp 1. 01 背包(限量) 假如有这几个物品&am…...
C++:反向迭代器的实现
反向迭代器的实现与 stack 、queue 相似,是通过适配器模式实现的。通过传入不同类型的迭代器来实现其反向迭代器。 正向迭代器中,begin() 指向第一个位置,end() 指向最后一个位置的下一个位置。 代码实现: template<class I…...
webGL入门教程_04vec3、vec4 和齐次坐标总结
vec3、vec4 和齐次坐标总结 1. vec3 和 vec4 1.1 什么是 vec3 和 vec4? vec3: GLSL 中的三维向量类型,包含 3 个浮点数:(x, y, z)。常用于表示三维坐标、RGB 颜色、法线、方向等。 vec4: GLSL 中的四维向量类型&…...
uniapp中父组件数组更新后与页面渲染数组不一致实战记录
简单描述一下业务场景方便理解: 商品设置功能,支持添加多组商品(点击添加按钮进行增加).可以对任意商品进行删除(点击减少按钮对选中的商品设置进行删除). 问题: 正常添加操作后,对已添加的任意商品删除后,控制台打印数组正常.但是与页面显示不一致.已上图为例,选中尾…...
优化 Conda 下载速度:详细的代理配置和网络管理策略
优化 Conda 下载速度:详细的代理配置和网络管理策略 为了彻底解决使用 Conda 下载 PyTorch 时遇到的速度问题,并确保下载过程稳定可靠,这需要一个详细、综合的技术方案。让我们更深入地分析问题原因,然后详尽地解释采取的解决策略…...
服务器遭受DDoS攻击后如何恢复运行?
当服务器遭受 DDoS(分布式拒绝服务)攻击 后,恢复运行需要快速采取应急措施来缓解攻击影响,并在恢复后加强防护以减少未来攻击的风险。以下是详细的分步指南: 一、应急处理步骤 1. 确认服务器是否正在遭受 DDoS 攻击 …...
MFC音视频播放器-支持电子放大等功能
前言 本播放器在VS2019下开发,使用ffmpegD3D实现视频播放渲染功能。同时本播放器支持录像功能、截图功能、音视频播放功能、码流信息显示、电子放大功能等。D3D的渲染同时支持surface和texture两种方式,电子放大功能是在D3D Texture方式下进行实现。以下…...
c语言编程1.17蓝桥杯历届试题-回文数字
题目描述 观察数字:12321,123321 都有一个共同的特征,无论从左到右读还是从右向左读,都是相同的。这样的数字叫做:回文数字。 本题要求你找到一些5位或6位的十进制数字。满足如下要求: 该数字的各个数位之…...
el-table 纵向 横向 多级表头
<el-table :data"tableData" class"diaTable":span-method"handleSpanMethod"border:header-cell-style"{background:#292929,color:#fff}"><!-- 纵向表头 --><el-table-column label"纵向表头" width"…...
uniapp开发微信小程序笔记8-uniapp使用vant框架
前言:其实用uni-app开发微信小程序的首选不应该是vant,因为vant没有专门给uni-app设置专栏,可以看到目前Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本,并由社区团队维护 React 版本和支付宝小程序版本。 但是vant的优…...
分布式项目使用Redis实现数据库对象自增主键ID
hello。大家好,我是灰小猿,一个超会写bug的程序猿! 在分布式项目中,数据表的主键ID一般可能存在于UUID或自增ID这两种形式,UUID好理解而且实现起来也最容易,但是缺点就是数据表中的主键ID是32位的字符串&a…...
npm-运行项目报错:A complete log of this run can be found .......npm-cache_logs\
1.问题 没有找到对应的某种依赖,node_modules出现问题。 2.解决 (1)查看对应依赖是否引入或者是由于合并分支错误 引入js或依赖不存在。谨慎删除依赖包 (2)查找对应引入依赖进行安装最后解决方法-删除依赖包清除缓存 npm cache clean --force (2)重新向同事引入…...
SolarCube: 高分辨率太阳辐照预测基准数据集
太阳能作为清洁能源在减缓气候变化中的作用日益凸显,其稳定的供应对电网管理至关重要。然而,太阳辐照受云层和天气变化的影响波动较大,给光伏电力的管理带来挑战,尤其是在调度、储能和备用系统管理方面。因此,精确的太…...
华为小米苹果三星移动设备访问windows共享文件夹windows11
如果移动设备和windows电脑都在同一个局域网内,可以用移动设备访问windows11的共享文件夹 1、设置共享文件夹 2、添加everyone用户即可 3、查看ip地址 4、在华为手机上点击文件管理,里面有个网上邻居 5、正常情况下,华为手机会扫描到同一局域…...
网络安全三防指南:只防病毒不安全
5月17日,瑞星全球反病毒监测网截获一个恶性病毒,由于该病毒的破坏能力和当年著名的CIH病毒几乎完全一样,因此瑞星将该病毒命名为“新CIH”病毒。被“新CIH”感染的电脑,主板和硬盘数据将被破坏,致使电脑无法启动&#…...
论文概览 |《Urban Analytics and City Science》2023.05 Vol.50 Issue.4
本次给大家整理的是《Environment and Planning B: Urban Analytics and City Science》杂志2023年5月第50卷第4期的论文的题目和摘要,一共包括19篇SCI论文! 论文1 Data analytics and sustainable urban development in global cities 全球城市的数据…...
【ROS2】ROS2 C++版本 与 Python版本比较
ROS 系列学习教程(总目录) ROS2 系列学习教程(总目录) 目录 一、功能包的构建方式二、功能包组织结构三、代码编写四、性能与效率五、兼容性六、应用场景 目前ROS开发主要使用 C 和 Python 语言,这里会分别实现并讲解。 相较于ROS1,ROS2的 C 和 Python …...
辽宁城乡建设部网站首页/推销产品的软文500字
StringBuilder和StringBuffer是可变字符序列 区别: StringBuilder的线程不安全,但是效率高。 StringBuffer的线程安全,但是效率低。 StringBuilder: StringBuilder sb new StringBuilder(); //这里初始化一个默认长度16的char数组…...
重庆网站建设与网络推广/怎样制作一个网站
Java几种常见的四舍五入的方法 题目要CSS布局HTML小编今天和大家分享编写一个四舍五入的函数,要CSS布局HTML小编今天和大家分享可以保留到小数点后面的任意一位。 java四舍五入的函数:Math.round 语法: Math.round(x); 参数: x 为一数值。 解释: 方法。返回对参数x四舍五入…...
soho在哪里做网站/产品网络营销策划
JavaScript,DOM操作表格 学习要点: 1.操作表格 DOM在操作生成HTML上,还是比较简明的。不过,由于浏览器总是存在兼容和陷阱,导致最终的操作就不是那么简单方便了。本章主要了解一下DOM操作表格和样式的一些知识。 一&am…...
wordpress网站迁移问题/爱站网站长seo综合查询
什么是拦截器 1.SpringMVC框架中的拦截器用于 对处理器 进行预处理和后处理的技术。 2.可以定义拦截器链,按照顺序执行。 3.拦截器和过滤器功能类似,区别在 拦截器过滤器过滤器是Servlet规范的一部分,任何框架都可以使用过滤技术。而拦截器是…...
网站建设运营方案/域名停靠网页推广大全2021
实战需求 SwiftUI 制作个音乐播放器 本文价值与收获 看完本文后,您将能够作出下面的界面 截屏2020-08-18 下午3.59.50.png看完本文您将掌握的技能...
surface go 网站开发/网站收录免费咨询
GIT分支 分支在GIT中相对较难,分支就是科幻电影里面的平行宇宙,如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,我们就需要处理一些问题了! git br…...