常用排序算法(下)

目录

2.5 冒泡排序

2.6 快速排序

2.6 1 快速排序思路

详细步骤

2.6 2 快速排序递归实现 

2.6 3快速排序非递归:

快排非递归的优势

 非递归思路

1. 初始化栈

2. 将整个数组的起始和结束索引入栈

3. 循环处理栈中的子数组边界

4. 单趟排序

5. 处理分区后的子数组

6. 重复步骤3和步骤5

注意事项

2.7 归并排序

基本思想:

一、算法步骤

二、具体实现

归并排序递归实现:

归并排序非递归实现: 

三、性能分析

2.8 计数排序

计数排序概念:

一、计数排序的原理与步骤

二、计数排序的示例

 计数排序代码实现:

三、注意事项

四、计数排序的特点


2.5 冒泡排序

   基本思路

    冒泡排序的基本思路是通过重复遍历待排序的数列,比较每对相邻元素的值,若发现顺序错误则交换它们的位置。这个过程重复进行,直到没有需要交换的元素为止,此时数列就完成了排序。冒泡排序的名字是因为较小的元素会逐渐“冒泡”到数列的顶端,即前面,而较大的元素则会沉到数列的底部,即后面。
冒泡排序的基本步骤如下:
(1)比较相邻的元素。如果第一个比第二个大,就交换它们两个。
(2)对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
(3)针对所有的元素重复以上的步骤,除了最后一个。
(4)持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序的时间复杂度在最坏情况下是O(n^2),其中n是数列的长度。尽管冒泡排序不是最高效的排序算法,但它的实现简单,对于小数据量的排序问题还是相当实用的。

  动图展示:

代码实现:

void BubbleSort(int* a, int n)
{for (int i = 1; i < n-1; i++){int flag = 0;for (int j = 0; j < n - i ; j++){if (a[j] > a[j + 1]){Swap(&a[j], &a[j + 1]);flag = 1;}}if (flag == 0){break;}}
}

 问:程序中的flag的作用是什么?

答:冒泡排序时间复杂度是O(N^2),但是这个时间复杂度是由这个算法的最坏情况决定的,也就是当我们要排升序时,我们给了一个降序的数组,这时这个程序的时间复杂度就是O(N^2),而在这个组相对有序的情况下 ,我们可以使用一些手段来提高这个算法的效率,而这个flag就是我们优化这个算法的关键。

   我们知道,如果一个相对有序甚至有序组因该是比无序的数组排序的速度更快的,但是,我们需要判断何时有序,像这个程序中我们使用了两个for循环,如果不判断何时有序然后结束程序的话,它就会完完整整地将这两个循环走完,也就是说,无论是有序还是无序的一组数来排序它的时间复杂度都是O(N^2)。这时我们就可以定义一个flag变量,将它初始化为0,如果里面有数排序了,说明这个数组是无序的,将flag置为1,下一次循环又将flag置为0,我们在下面判断,如果flag为0的话,就说明这个数组没有元素交换过,也就是说这个数组是有序的,既然它是有序的,我们就马上结束这个程序,这样优化我们的冒泡排序就不会每次进入它的时间复杂度都是O(N^2)了,如果这个数组是有序的,那么只会遍历一遍数组就结束程序,此时它的速度是0(N)。

2.6 快速排序

    快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

2.6 1 快速排序思路

快速排序(Quick Sort)是一种高效的排序算法,它使用分治策略来对一个数组进行排序。以下是快速排序的基本思路:

  1. 选择基准
    从数组中选择一个元素作为基准(key)。这个基准可以是数组中的第一个元素、最后一个元素、中间元素,或者通过某种方式随机选择的元素。

  2. 分区
    重新排列数组,使得所有小于基准的元素都位于基准的左侧,所有大于基准的元素都位于基准的右侧。这个操作称为分区(partition)。

  3. 递归排序
    对基准左侧和右侧的子数组分别进行快速排序。这是一个递归的过程,直到子数组的大小为零或一(此时子数组已经是有序的)。

  4. 合并
    由于快速排序是原地排序,且通过递归已经保证了每个子数组的有序性,所以最终整个数组也会是有序的,不需要额外的合并步骤。

详细步骤

  1. 初始化

    • 设定数组的起始位置 left和结束位置 right
  2. 选择基准

    • 选择数组中的一个元素作为基准,通常选择 array[right](也可以选择其他元素)。
  3. 分区

    • 初始化一个指针 i,使其指向数组的起始位置 low
    • 遍历数组,从 left 到 right-1
      • 如果 array[i] <= key,则继续向右移动 i
      • 如果 array[i] > key,则交换 array[i] 和 array[righth-1](或者任何一个大于key 的未处理元素的位置),并将 right-1 向左移动一位(因为该位置已经处理过)。
    • 最后,将基准元素key 放到正确的位置上,即 array[i] 和 array[right] 之间(通常是通过交换 array[i] 和 array[right] 来完成)。
  4. 递归排序

    • 对基准左侧的子数组(left到 i-1)进行快速排序。
    • 对基准右侧的子数组(i+1 到 right)进行快速排序。
  5. 结束条件

    • 当子数组的大小为零或一时,递归结束,数组已经有序。

2.6 2 快速排序递归实现 

  到现在为止,我们已经了解了快速排序的大致思路,先来看递归实现的快速排序:

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
int GetMiddle(int* a, int left, int right)
{int mid = left + right + 1;if (a[left] < a[mid]){if (a[right] > a[mid]){return mid;}else if (a[right] > a[left]){return right;}else{return left;}}else //a[left]>a[mid]{if (a[right] > a[left]){return left;}else if (a[right] > a[mid]){return right;}else{return mid;}}
}void QuickSort(int* a, int left, int right)
{if (left >= right){return;}
//当left大于或等于right时,说明数组已经有序if ((left + right + 1) < 10){InsertSort(a + left, left + right + 1);
//假设快排递归将被排序数组分散成了
//一棵二叉树,我们知道二叉树的最后一层
//占了这棵树的大半结点,当左右加起来
//的数据少于10时,我们可以使用
//插入排序提高它的效率}else{//三数取中int mid = GetMiddle(a, left, right);Swap(&a[left], &a[mid]);int keyi = left;int begin = left, end = right;while (begin < end){while (begin < end && a[end] >= a[keyi]){end--;}while (begin < end && a[begin] <= a[keyi]){begin++;}Swap(&a[begin], &a[end]);}Swap(&a[keyi], &a[begin]);keyi = begin;QuickSort(a, left, keyi - 1);QuickSort(a, keyi + 1, right);}
}

使用一组无序的数来测试一下:

int a[] = { 3,5,8,6,9,7,4,1,2,0,10 };

注意:此程序中的插入排序和三数取中算法都是为了优化快速排序,使它拥有更好的效率,快速排序的核心逻辑代码为:

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;}//当left大于或等于right时,说明数组已经有序int keyi = left;int begin = left, end = right;while (begin < end){while (begin < end && a[end] >= a[keyi]){end--;}while (begin < end && a[begin] <= a[keyi]){begin++;}Swap(&a[begin], &a[end]);}Swap(&a[keyi], &a[begin]);keyi = begin;QuickSort(a, left, keyi - 1);QuickSort(a, keyi + 1, right);
}

2.6 3快速排序非递归:

  看到这里,小伙伴们不禁疑惑:我们既然可以使用递归实现快速排序,为什么还要使用非递归实现呢?

快排非递归的优势

快速排序非递归实现的重要性主要体现在以下几个方面:

  1. 避免递归调用开销:递归实现虽然直观易懂,但在一些编程语言中,递归调用会引入额外的函数调用栈的使用和维护开销。非递归实现通过显式地使用栈来管理状态,可以有效避免这些开销,从而提高性能。

  2. 防止栈溢出:在极端情况下,递归实现可能导致栈溢出,尤其是在处理大规模数据时。非递归实现使用显式的数据结构(如栈)来管理状态,不依赖于系统的调用栈,从而避免了栈溢出的风险。

  3. 降低空间复杂度:递归实现可能需要更多的内存空间,因为每个递归调用都需要在内存中保留一些信息。非递归实现通常使用更少的内存,只需维护一些必要的状态信息,有助于减少内存使用。

  4. 提升性能:在某些编程语言和环境中,递归调用的性能可能不如循环,因为每个递归调用都需要函数调用的开销。非递归实现可以更好地与一些编译器和优化器协同工作,从而提高性能。

  5. 便于优化:非递归实现更容易进行一些优化,例如通过使用迭代而不是递归的方式来访问数组,以更好地利用CPU缓存。这种优化可以进一步提升算法的执行效率。

  6. 适应特定场景:在一些对递归深度有限制的环境(如嵌入式系统)中,非递归实现是必须的,以确保算法能够正常运行。

 非递归思路

快速排序的非递归思路主要是通过手动管理一个栈来模拟递归过程中的函数调用栈,从而实现对数组的排序。以下是快速排序非递归思路的详细步骤:

1. 初始化栈

  • 创建一个空栈,用于保存接下来需要排序的子数组的边界。这个栈可以是任意类型的栈结构,但通常使用整型栈来保存子数组的起始索引(left)和结束索引(right)。

2. 将整个数组的起始和结束索引入栈

  • 这一步相当于递归排序中的初始调用。将数组的起始索引(left)和结束索引(right)作为一对入栈,表示接下来需要处理整个数组。

3. 循环处理栈中的子数组边界

  • 不断从栈中弹出子数组的边界索引(一对),然后对这个子数组进行快速排序的单趟排序。

4. 单趟排序

  • 在单趟排序中,首先选择一个元素作为基准(pivot)。基准的选择可以是子数组的第一个元素,也可以通过其他策略(如三数取中法)来选择。
  • 进行分区操作,将子数组划分为比基准小的左侧部分和比基准大的右侧部分,并确定基准元素的最终位置。

5. 处理分区后的子数组

  • 分区操作完成后,基准元素左侧的子数组(如果存在)和右侧的子数组(如果存在)可能还需要继续排序。
  • 如果左侧子数组有多个元素,则将其起始和结束索引作为一对入栈。
  • 如果右侧子数组有多个元素,也将其起始和结束索引作为一对入栈。

6. 重复步骤3和步骤5

  • 继续迭代该过程,直到栈为空。此时,所有的子数组都已经被正确排序,整个数组也就完成了排序。

注意事项

  • 在单趟排序中,分区操作是关键步骤,它决定了基准元素的最终位置,并将数组划分为两个子数组。
  • 栈的使用是非递归快速排序的核心,它模拟了递归调用栈的功能,允许我们手动管理子数组的排序顺序。
  • 非递归快速排序的性能与递归快速排序相近,但在某些情况下(如递归深度过大导致栈溢出)可能更加稳定可靠。

总结:通过以上步骤,我们可以实现快速排序的非递归版本,从而在处理大规模数据时避免递归调用栈的限制。

由于c语言没有STL,我们使用c++来实现:

int GetMiddle(int* a, int left, int right)
{int mid = left + right + 1;if (a[left] < a[mid]){if (a[right] > a[mid]){return mid;}else if (a[right] > a[left]){return right;}else{return left;}}else //a[left]>a[mid]{if (a[right] > a[left]){return left;}else if (a[right] > a[mid]){return right;}else{return mid;}}
}
int PartSort1(int* a, int left, int right)
{// 三数取中int midi = GetMiddle(a, left, right);Swap(&a[left], &a[midi]);int keyi = left;int begin = left, end = right;while (begin < end){// 右边找小while (begin < end && a[end] >= a[keyi]){--end;}// 左边找大while (begin < end && a[begin] <= a[keyi]){++begin;}Swap(&a[begin], &a[end]);}Swap(&a[keyi], &a[begin]);return begin;
}//非递归
void QuickSortNonR(int* a, int left, int right)
{stack<int> st;st.push(right);st.push(left);while (!st.empty()){int begin = st.top();st.pop();int end = st.top();st.pop();int keyi = PartSort1(a, begin, end);if (keyi+1 < end){st.push(end);st.push(keyi+1);}if (begin < keyi - 1){st.push(keyi - 1);st.push(begin);}}
}

我们来测试一下:

可以看到我们的快排非递归也是成功地实现了。

快速排序的特性总结

1. 快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
2. 时间复杂度:O(N*logN)

3. 空间复杂度:O(logN)
4. 稳定性:不稳定 

总结:快速排序是一种非常高效的排序算法,尤其适用于大部分元素已经有序的情况。通过合理选择基准和优化递归过程,可以进一步提高其性能

2.7 归并排序

基本思想:

   归并排序(Merge Sort)是一种分治策略的排序算法,其基本思想是将一个序列分为两个较小的子序列,直到子序列的大小为1,然后将已排序的子序列合并成一个大的有序序列。以下是归并排序的完整思路:

一、算法步骤

  1. 分割

    • 将待排序的数组分成两半,如果数组长度为奇数,则其中一部分会比另一部分多一个元素。
    • 对这两部分数组继续递归地进行分割,直到子数组的长度为1,此时可以认为每个子数组都是有序的(因为只有一个元素)。
  2. 治理(解决)

    • 这一步在归并排序中实际上是通过分割步骤隐含完成的。当子数组的长度为1时,它们自然就是有序的,无需进一步处理。
  3. 合并

    • 将相邻的有序子数组合并成一个有序数组,直到合并为1个完整的数组。
    • 合并过程中,通过比较两个子数组的元素,按大小顺序依次放入新的数组中,从而实现排序。

二、具体实现

  1. 申请空间

    • 创建一个临时数组,用于存放合并后的子数组。
  2. 设定指针

    • 在两个待合并的子数组上分别设置指针,初始时都指向子数组的起始位置。
  3. 比较合并

    • 比较两个指针所指向的元素,将较小的元素放入临时数组,并移动该指针。
    • 重复此过程,直到某个子数组的所有元素都被复制到临时数组中。
    • 将另一个子数组中剩余的元素(如果有的话)直接复制到临时数组的末尾。
  4. 复制回原数组

    • 将临时数组中的元素复制回原数组,以替换原来的子数组。

归并排序递归实现:

void _MergeSort(int* a, int* tmp,int begin,int end)
{if (begin >= end){return;}int mid = (begin + end) / 2;_MergeSort(a, tmp, begin, mid);_MergeSort(a, tmp, mid+1, end);int begin1 = begin, end1 = mid;int begin2 = mid+1, end2 = end;int i = begin;while (begin1 <= end1 && begin2 <= end2){if(a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));}
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");}_MergeSort(a, tmp, 0, n - 1);free(tmp);tmp = NULL;}

此程序涉及在堆上申请资源,所以我们分两个接口实现。

归并排序非递归实现: 

//归并排序非递归
void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * (n+1));if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap <= n){for (int j = 0; j <= n;j+=gap*2){int begin1 = j, end1 = j + gap - 1;int begin2 = j + gap, end2 = j + gap * 2 - 1;if (begin2 > n ){break;}if (end2 > n){end2 = n;}int i = j;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + j, tmp + j, sizeof(int) * (end2 - j+1));}gap *= 2;}free(tmp);tmp == NULL;}

给一组无序数,我们来测试一下:

int a[] = { 3,5,7,1,2,0,9,10,4,8,11 };

 

可以看到没有什么问题。

 

三、性能分析

  • 时间复杂度:归并排序的时间复杂度为O(n log n),其中n是数组的长度。在每一层递归中,合并操作的时间复杂度为O(n),而递归的层数为log n,因此总的时间复杂度为O(n log n)。
  • 空间复杂度:归并排序的空间复杂度也是O(n),因为需要额外的空间来创建临时数组。
  • 稳定性:归并排序是稳定的排序算法,即相等的元素在排序后的顺序与它们在原数组中的顺序相同。

总结:归并排序因其稳定的排序特性和较好的平均性能,在实际应用中非常广泛。特别是在数据量较大时,归并排序能够展现出其高效的排序能力。 

2.8 计数排序

计数排序概念:

     计数排序(Counting Sort)是一种非基于比较的排序算法,由Harold H. Seward在1954年提出。它适用于待排序元素为整数且范围较小的情况。计数排序的基本思想是统计每个元素的出现次数,然后利用这些信息将原始序列重新组合成有序序列。

一、计数排序的原理与步骤

计数排序的工作原理主要包括以下几个步骤:

  1. 统计元素出现次数

    • 遍历待排序的数组,统计每个元素出现的次数。这通常通过创建一个辅助数组(计数数组)来实现,该数组的长度等于待排序数组中元素的最大值加1(如果元素是非负整数)。
  2. 前缀和操作

    • 对计数数组进行前缀和操作,使得每个元素的值变为小于等于该元素的值的元素总数。这样,计数数组的每个位置就对应了原数组中元素在排序后数组中的位置。
  3. 重建有序数组

    • 遍历待排序数组,根据计数数组的信息,将元素放回其在有序数组中的正确位置。同时,更新计数数组中对应元素的值,以确保相同元素的相对顺序不变。

二、计数排序的示例

假设我们有一个待排序的数组arr = [4, 2, 2, 8, 3, 3, 1],我们可以按照计数排序的步骤对其进行排序:

  1. 统计元素出现次数

    • 遍历数组arr,得到计数数组count = [0, 1, 2, 2, 2, 0, 1, 1](假设数组中的元素都是非负整数,且最大值不超过7)。
  2. 前缀和操作

    • 对计数数组进行前缀和操作,得到count = [0, 1, 3, 5, 7, 7, 7, 8]。
  3. 重建有序数组

    • 遍历数组arr,根据计数数组的信息将元素放回有序数组中的正确位置。排序后的数组为sorted_arr = [1, 2, 2, 3, 3, 4, 8]。
 计数排序代码实现:
void CountSort(int* a, int n)
{int max = a[0], min = a[0];for (int i = 0; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}int range = max - min + 1;int* count = (int*)calloc(range, sizeof(int));if (count == NULL){perror("calloc fail");}for (int i = 0; i <n; i++){count[a[i] - min]++;}int j = 0;for (int i = 0; i < range; i++){while (count[i]--){a[j++] = i + min;}}}

给一组无序数测试一下:

int a[] = { 2,4,76,87654,98,12,76,454,23,98 };

 

    虽然我们的排序成功了,但是这个程序内部开辟了非常多的空间,所以当一组数的最大值和最小值相差太多时,不建议使用计数排序

三、注意事项

  • 在使用计数排序时,需要确保待排序数组中的元素都是非负整数或可映射到非负整数范围内。如果待排序的元素不满足这个要求,就需要对其进行映射转换。
  • 当待排序元素的范围非常大时,计数排序可能会消耗大量的内存空间,因此在实际应用中需要注意这一点。

四、计数排序的特点

  1. 时间复杂度

    • 计数排序的时间复杂度为O(n+k),其中n是待排序数组的长度,k是待排序数组中元素的范围。当k不是很大时,计数排序的时间复杂度接近线性,快于任何基于比较的排序算法(如快速排序、归并排序等,它们的时间复杂度在理论上的下限是O(n log n))。
  2. 空间复杂度

    • 计数排序的空间复杂度为O(k),其中k是待排序数组中元素的范围。因此,计数排序是一种牺牲空间换取时间的排序算法。
  3. 稳定性

    • 计数排序是稳定的排序算法,即相等的元素在排序后的序列中保持它们原有的先后顺序。
  4. 适用场景

    • 计数排序特别适用于整数排序,特别是当整数的范围不是很大时。对于非整数类型的数据或整数范围非常大的情况,计数排序可能不适用或效率较低。

 本章完。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/439265.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文速看】DL最新进展20241005-Transformer、目标跟踪、Diffusion Transformer

目录 【Transformer】【目标跟踪】【Diffusion Transformer】 【Transformer】 [NeurlPS 2024] Parameter-Inverted Image Pyramid Networks 机构&#xff1a;清华大学、上海AI Lab、上交、港中文、商汤 论文链接&#xff1a;https://arxiv.org/pdf/2406.04330 代码链接&…

C++ | Leetcode C++题解之第454题四数相加II

题目&#xff1a; 题解&#xff1a; class Solution { public:int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {unordered_map<int, int> countAB;for (int u: A) {for (int v: B) {count…

网络基础 【HTTPS】

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;Linux初窥门径⏪   &#x1f69a;代码仓库:Linux代码练习&#x1f69a; &#x1f4bb;操作环境&#xff1a; CentOS 7.6 华为云远程服务器 &#x1f339;关注我&#x1faf5;带你学习更多Linux知识…

LabVIEW提高开发效率技巧----调度器设计模式

在LabVIEW开发中&#xff0c;针对多任务并行的需求&#xff0c;使用调度器设计模式&#xff08;Scheduler Pattern&#xff09;可以有效地管理多个任务&#xff0c;确保它们根据优先级或时间间隔合理执行。这种模式在需要多任务并发执行时特别有用&#xff0c;尤其是在实时系统…

软件验证与确认实验一:静态分析

目录 1. 实验目的及要求.................................................................................................... 3 2. 实验软硬件环境.................................................................................................... 3 …

JAVA运用中springBoot获取前端ajax提交参数方式汇总

本篇文章主要讲解springboot获取前端提交的参数信息&#xff0c;后端进行接受的常见方法汇总&#xff0c;通过本篇文章你可以快速掌握对表单和连接参数获取的能力。 作者&#xff1a;任聪聪 日期&#xff1a;2024年10月5日 一、delete、get等url参数获取方式 前台提交&#xf…

数字图像处理:空间域滤波

1.数字图像处理&#xff1a;空间域滤波 1.1 滤波器核&#xff08;相关核&#xff09;与卷积 图像上的邻域计算 线性空间滤波的原理 滤波器核&#xff08;相关核&#xff09;是如何得到的&#xff1f; 空间域的卷积 卷积&#xff1a;滤波器核与window中的对应值相乘后所有…

【Echarts】折线图和柱状图如何从后端动态获取数据?

&#x1f680;个人主页&#xff1a;一颗小谷粒 &#x1f680;所属专栏&#xff1a;Web前端开发 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 1.1 前端数据分析 1.2 数据库表分析 1.3 后端数据处理 1.4 前端接收数据 继上一篇文章&…

MySQL 查询优化器

文章目录 控制查询计划optimizer_prune_leveloptimizer_search_depth 优化器参数优化器提示索引提示成本模型server_costcost_name engine_cost 控制查询计划 https://dev.mysql.com/doc/refman/8.4/en/controlling-query-plan-evaluation.html 在执行SQL前会根据优化器选择执…

C++_智能指针详解

什么是智能指针&#xff1f;为什么要有智能指针&#xff1f;到目前为止&#xff0c;我们编写的程序所使用的对象都有着严格定义的生命周期。比如说&#xff0c;全局对象在程序启动时分配&#xff0c;在程序结束时销毁&#xff1b;再比如说局部static对象在第一次使用前分配&…

electron-builder 首次执行报错问题解决

假日想研究一下 react electron 的使用&#xff0c;结果发现首次打包疯狂报错&#xff0c;研究了一下之后才发现是第一次的话 electron-builder 会从外面下载依赖包到我们系统中&#xff0c;由于某种力量导致压缩包无法下载或者是下载过慢导致失败&#xff0c;要解决其实也简单…

初学51单片机之I2C总线与E2PROM二

总结下上篇博文的结论&#xff1a; 1&#xff1a;ACK信号在SCL为高电平期间会一直保持。 2&#xff1a;在字节数据传输过程中如果发送电平跳变&#xff0c;那么电平信号就会变成重复起始或者结束的信号。&#xff08;上篇博文的测试方法还是不能够明确证明这个结论&#xff0…

【C++】入门基础介绍(上)C++的发展历史与命名空间

文章目录 1. 前言2. C发展历史2. 1 C版本更新特性一览2. 2 关于C23的一个小故事: 3. C的重要性3. 1 编程语言排行榜3. 2 C在工作领域中的应用 4. C学习建议和书籍推荐4. 1 C学习难度4. 2 学习书籍推荐 5. C的第一个程序6. 命名空间6. 1 namespace的价值6. 2 namespace的定义6. …

首届中美可持续发展峰会在加州圆满举行,引领国际绿色发展新方向

现场嘉宾与(部分)与会人员大合影 2024年8月18日,由美国领创商业联盟(Youth Entrepreneur Business Alliance, YEBA)主办的首届中美可持续发展峰会(Sino-American Symposium on Sustainable Development)在加州森林湖市(Lake Forest)盛大举行。此次峰会吸引了数百名来自中美两国…

HTML+CSS之表格(15个案例+代码+效果图+素材)

目录 1.table标签的border属性 案例:制作一个带边框的表格 1.代码 2.效果 2.table标签的cellspacing属性 案例:制作一个带边距的表格 1.代码 2.效果 3.table标签的cellpadding属性 1.代码 2.效果 4.table标签的width和height属性 案例:指定宽高的表格 1.代码 2.效果 5.table标签…

全新芒果YOLOv10改进135:最新注意力机制EMA:即插即用,具有跨空间学习的高效多尺度注意力模块,ICCASSP 2023

💡本篇内容:芒果YOLOv10改进135:最新注意力机制EMA:即插即用,具有跨空间学习的高效多尺度注意力模块,ICCASSP 2023 **具有跨空间学习的高效多尺度注意力模块EMA | 即插即用 该模块通常包括多个并行的注意力子模块,每个子模块关注于输入数据的不同尺度或分辨率。这些子模块…

HTML+CSS表单控件(11个案例+代码+效果图)

目录 单行文本框 (text) 案例:制作一个单行文本框 1.代码 2.效果 密码输入框 (password) 案例:制作密码输入框 1.代码 2.效果 单选按钮 (radio) 案例:制作单选按钮 1.代码 2.效果 复选框 (checkbox) 案例:制作一个复选框 1.代码 2.效果 普通按钮 (button) 案例:制作一个普通按钮…

Java毕业设计实战项目之基于SSM框架的民宿预定系统

项目技术架构&#xff1a; 该SSMVue的民宿预定系统&#xff0c;后端采用SSM架构&#xff0c;前端采用VueElementUI实现页面的快速开发&#xff0c;并使用关系型数据库MySQL存储系统运行数据。本系统分为三种角色&#xff0c;分别是系统管理员&#xff0c;用户&#xff0c;房主…

RD-Agent Windows安装教程

RD-Agent Windows安装教程 QuantML QuantML 2024年09月23日 18:30 Content RD-Agent 是微软亚洲研究院推出的一款自动化研究与开发工具&#xff0c;能够通过LLMs自动构建因子和策略&#xff0c;相关介绍见我们之前的文章&#xff1a;RD-Agent &#xff1a;自动化Quant工厂 然…

10.5二分专练,二分边界情况,+1不加1的判断,方向判断,各种DEBUG

5 https://leetcode.cn/problems/minimum-speed-to-arrive-on-time/submissions/570242512/ 就是说总时间是 前n-1量汽车的运行时间&#xff0c;向上取整&#xff0c;然后再加上最后一辆列车的运行时间 最快的话是需要n-1个小时 搜索空间就是时速&#xff0c;左边界是1&#x…