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

初阶5 排序

本章重点

  1. 排序的概念
  2. 常见排序的算法思想和实现
  3. 排序算法的复杂度以及稳定性分析

1.排序的概念

  • 排序: 所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
  • 稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
  • 内部排序: 数据元素全部放在内存中的排序。
  • 外部排序: 数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

2.常见比较排序的算法思想和实现(默认升序)

2.1 插入排序

2.1.1 直接插入排序

基本思想:

直接插入排序是一种简单的排序算法
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

当插入第i(i>=1)个元素时,前面的array[0],array[1],…,array[i-1]已经排好序,此时用array[i]的排序码与array[i-1],array[i-2],…的排序码顺序进行比较,找到插入位置即将array[i]插入,原来位置上的元素顺序后移

性能总结:

  • 元素集合越接近有序,直接插入排序算法的时间效率越高(最好时,时间复杂度:O(N))
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1),它是一种稳定的排序算法
  • 稳定性:稳定
void InsertSort(int* a, int n)
{//两层循环    第一层是用来确顶当前该比较哪个位置的数,用tmp来记录//		     第二层是用来进行从end到0方向的下标位置比较,//                  用tmp与之前的所有位置的数进行比较for (int i = 1; i < n ; i++){int end = i-1;int tmp = a[i];while (end >= 0){if (tmp > a[end]){a[end + 1] = a[end];--end;}else{break;}}a[end + 1] = tmp;}
}

2.1.2 希尔排序(缩小增量法)

基本思想:

先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

性能总结:

  • 希尔排序是对直接插入排序的优化
  • 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比
  • 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定
    希尔排序的时间复杂度和堆排序的复杂度差不多(约 N1.3 ),但在数据越大的情况下希尔排序更好
  • 稳定性:不稳定
void ShellSort(int* a, int n)
{// 三层循环,第一层:对gap的递减,达成预排序//			 第二层和第三层的方法就和直接插入排序一样了// // gap > 1 预排序// gap == 1 直接插入排序int gap = n;while (gap > 1){gap = gap / 2;for (int i = 0; i < n - gap; ++i){int end = i;int tmp = a[end + gap];while (end >= 0){if (tmp < a[end]){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}

2.2 选择排序

2.2.1 直接选择排序

基本思想:

每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完 。

也可以一次循环直接将最小和最大都选出来(如下面代码中那样)

步骤:

  • 在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素
  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个
    (第一个)元素交换
  • 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

特性总结:

  • 直接选择排序思考非常好理解,但是效率不是很好。实际中很少使用
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:不稳定

直接选择排序在任何情况都是O(N^2) 包括有序或接近有序,
所以它的排序效率还没有直接插入排序的效率高

//交换
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}void SelectSort(int* a, int n)
{int begin = 0, end = n - 1;while (begin < end){int mini = begin, maxi = begin;for (int i = begin + 1; i <= end; ++i){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}Swap(&a[begin], &a[mini]);// 这里是防止maxi和begin相等时,由于换位而导致maxi的交换发生错误if (maxi == begin){	maxi = mini;}Swap(&a[end], &a[maxi]);++begin;--end;}
}

2.2.2 堆排序

基本思想:

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

请添加图片描述

特性总结:

  • 堆排序使用堆来选数,效率就高了很多。
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(1)
  • 稳定性:不稳定
//交换
void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
//像下调整(建大堆)(数组、数组大小、父节点下标)
void AdjustDown(int* a, int n, int parent)
{//默认认为左孩子大int child = parent * 2 + 1;//超过数组大小while (child < n){//确认child指向大的孩子if (child + 1 < n && a[child + 1] > a[child]) //第一处:a[child + 1] > a[child]{++child;}//孩子大于父亲,交换,继续调整//这里换为 > 是大堆的创建if (a[child] > a[parent])  //第二处:a[child] > a[parent]{swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else{break;}}//将第一处和第二处的>换为<则是建小堆
}
//堆排序
void HeapSort(int* a, int size)
{// 向下调整建堆 -- O(N)// 升序:建大堆for (int i = (size - 1 - 1) / 2; i >= 0; --i){AdjustDown(a, size, i);}int end = size - 1;//(end表示数组需要与array[0]交换的下标位置)while (end > 0){Swap(&a[0], &a[end]);//交换array[0]和array[end]的位置AdjustDown(a, end, 0);//向下调整end--;}
}

2.3 交换排序

所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,

交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。

2.3.1 冒泡排序

基本思想:

用当前的和前一个进行比较,将值大的往后移动,值小的往前移动。

冒泡排序也时最简单,最常学习的排序,缺点就是排序效率比较差

特性总结:

  • 冒泡排序是一种非常容易理解的排序
  • 时间复杂度:O(N^2)
  • 空间复杂度:O(1)
  • 稳定性:稳定
void BubbleSort(int* a, int n)
{for (int j = 0;j < n;j++){for (int i = 1;i < n - j;i++){if (a[i-1] > a[i]){int tmp = a[i - 1];a[i - 1] = a[i];a[i] = tmp;}}}
}

2.3.2 快速排序

基本思想:

任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止

请添加图片描述

单趟排序的作用:

  1. 使得key到了准确的位置
  2. 使得key左边的数都小于key,key右边的数都大于key

然后再对其递归排序数组key的左边和右边,最终就可排好序

注意的点:

  • 左边和右边都可以做key,但是
  • 左边做key,右边要先走
  • 右边做key,左边要先走
  • 这是为了保证相遇的位置,一定比key要小(左边做key的情况下)

三个坑:

  1. 越界
    修改:
    while (a[right] > a[keyi])改为
    while (left < right && a[right] > a[keyi])
  1. 死循环(存在与key相同数)
    修改:
    while (left < right && a[right] > a[keyi])改为
    while (left < right && a[right] >= a[keyi])
  1. 交换失败
    修改:
    Swap(&a[left], &key)改为
    Swap(&a[left], &a[keyi])

原因:

  • 未改变原数组值
  • 能适应更多类型的值
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int left = begin, right = end;int keyi = left;while (left < right){// 右边先走,找小while (left < right && a[right] >= a[keyi]){--right;}// 左边再走,找大while (left < right && a[left] <= a[keyi]){++left;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);keyi = left;// [begin, keyi-1]  keyi [keyi+1, end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi+1, end);
}

快速排序的优化

  1. 三数取中优化

原理:

选择最左边,最中间,最右边的三个数作比较,选出最小的数作为key

//快排改进:key选值的三数取中
int GetMidIndex(int* a, int begin, int end)
{int mid = (begin + end) / 2;if (a[begin] < a[mid]){if (a[mid] < a[end]){return mid;}else if (a[begin] > a[end]){return begin;}else{return end;}}else // a[begin] > a[mid]{if (a[mid] > a[end]){return mid;}else if (a[begin] < a[end]){return begin;}else{return end;}}
}
void MidQuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int mid = GetMidIndex(a, begin, end);Swap(&a[begin], &a[mid]);int left = begin, right = end;int keyi = left;while (left < right){// 右边先走,找小while (left < right && a[right] >= a[key]){--right;}// 左边再走,找大while (left < right && a[left] <= a[key]){++left;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);keyi = left;// [begin, keyi-1]  key [keyi+1, end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}
  1. 小区间优化(主要对空间进行优化):

到最后10个数的时候,用递归的话,可以看到还需要4层深度的递归
对最后一小段区域的排序,我们用直接插入排序就行

//小区间优化(优化空间)
void SpaceQuickSort(int* a, int begin, int end)
{if (begin >= end){return;}if ((end - begin + 1) < 10){// 小区间用直接插入替代,减少递归调用次数InsertSort(a + begin, end - begin + 1);}else{int mid = GetMidIndex(a, begin, end);Swap(&a[begin], &a[mid]);int left = begin, right = end;int keyi = left;while (left < right){// 右边先走,找小while (left < right && a[right] >= a[keyi]){--right;}// 左边再走,找大while (left < right && a[left] <= a[keyi]){++left;}Swap(&a[left], &a[right]);}Swap(&a[left], &a[keyi]);keyi = left;// [begin, keyi-1]  keyi [keyi+1, end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}
}

快速排序的其他版本

  1. Hoare
    以上
  1. 挖坑法
    请添加图片描述
void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int left = begin, right = end;int key = a[left];int hole = left;while (left < right){// 右边先走,找小while (left < right && a[right] >= key){--right;}a[hole] = a[right];hole = right;// 左边再走,找大while (left < right && a[left] <= key){++left;}a[hole] = a[left];hole = left;}a[hole] = key;QuickSort(a, begin, hole - 1);QuickSort(a, hole + 1, end);
}
  1. 快慢指针法
void PointQuickSort(int* a, int begin, int end)
{if (begin > end){return;}//小区间优化if ((end - begin + 1) < 10){// 小区间用直接插入替代,减少递归调用次数InsertSort(a + begin, end - begin + 1);}else{//三数选中间优化int mid = GetMidIndex(a, begin, end);Swap(&a[begin], &a[mid]);//开始int prev = begin, cur = begin + 1;int keyi = prev;while (cur <= end){while (cur <= end){if (a[cur] >= a[keyi] && ++prev != cur)//++prev和cur的下标如果相等,就不要进行交换{Swap(&a[++prev], &a[cur]); //一定是先++prev,在用prev }cur++;}}Swap(&a[prev], &a[keyi]);PointQuickSort(a, begin, keyi -1 );PointQuickSort(a, keyi + 1, end);}
}

快速排序的非递归(栈)

//快速排序(非递归)
//利用堆实现的叫做深度优先
void QuickSortNonR(int* a, int begin, int end)
{ST st;StackInit(&st);StackPush(&st, begin);StackPush(&st, end);while (!StackEmpty(&st)){int right = StackTop(&st);StackPop(&st);int left = StackTop(&st);StackPop(&st);//进行一次快排int prev = left, cur = left + 1;int key = left;while (cur <= right){//++prev和cur的下标如果相等,就可以不用进行交换if (a[cur] < a[key] && ++prev != cur){Swap(&a[prev], &a[cur]); }cur++;}Swap(&a[prev], &a[key]);key = prev;// [left, key-1] keyi [key+1, right]if (key + 1 < right){StackPush(&st, key + 1);StackPush(&st, right);}if (left < key - 1){StackPush(&st, left);StackPush(&st, key - 1);}}StackDestroy(&st);
}

2.4 归并排序

基本思想:

  • 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,
  • 该算法是采用分治法(Divide andConquer)的一个非常典型的应用。
  • 将已有序的子序列合并,得到完全有序的序列;
  • 即先使每个子序列有序,再使子序列段间有序。
  • 若将两个有序表合并成一个有序表,称为二路归并。

原理图:
分解合并

第一层将一个数组分两个大组,
第二层再继续分,直到分成每组都只有一个为止
分解完了之后就是进行合并,每两个小数组,按顺序合并成一个大的数组
最终,合并称为一个有序的集合

请添加图片描述
请添加图片描述

归并排序是在原数组上进行的,用一个临时数组来做归并,把归并好的元素复制回原数组

//归并排序(递归实现)//归并子函数
//(在遇到需要malloc扩容的函数时,将malloc代码放入主函数,另写一个子函数用来完成递归)
void _MergeSort(int* a, int begin ,int end, int* temp)
{//最后只剩下一个数的时候就说明begin=end,返回if (begin >= end){return;}int mid = (begin + end) / 2;//[begin, mid] [mid+1, end] 递归让子区间都有序_MergeSort(a, begin, mid, temp);    //递归左半区_MergeSort(a, mid+1, end, temp);    //递归右半区//归并int begin1 = begin, end1 = mid;     //左区间[begin1, end1]int begin2 = mid + 1, end2 = end;   //右区间[begin2, end2]int i = begin;//如果左右两个区间都没有结束就继续,只要有一个区间结束就终止while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){temp[i++] = a[begin1++]; }else{temp[i++] = a[begin2++];}}//将没走到头的区间按顺序放到后面while (begin1 <= end1){temp[i++] = a[begin1++];}while (begin2 <= end2){temp[i++] = a[begin2++];}//将临时区间的数据拷贝回原数组memcpy(a + begin, temp + begin, sizeof(int) * (end - begin + 1));
}//归并主函数
void MergeSort(int* a, int n)
{int* temp = (int*)malloc(sizeof(int) * n);if (temp == NULL){perror("malloc fail");exit(-1);}_MergeSort(a, 0, n-1, temp);free(temp);temp = NULL;
}

归并排序的非递归写法
数据有 4 种情况

  1. 数的个数是4的倍数
  2. end1 越界
  3. begin2 越界
  4. end2 越界

请添加图片描述

void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int)*n);if (tmp == NULL){perror("malloc fail");exit(-1);}// 归并每组数据个数,从1开始,因为1个认为是有序的,可以直接归并int rangeN = 1;while (rangeN < n) {for (int i = 0; i < n; i += 2 * rangeN){// [begin1,end1][begin2,end2] 归并int begin1 = i, end1 = i + rangeN - 1;int begin2 = i + rangeN, end2 = i + 2 * rangeN - 1;int j = i;// end1 begin2 end2 越界的三种情况//一定需要按顺序进行判断,不然会出错//end1越界,情况1,//解决:直接退出本次循环,可以不让后面的进行归并,再下一次循环时再排序if (end1 >= n){break;}//begin2出界,情况2,//解决:直接退出本次循环,可以不让后面的进行归并,再下一次循环时再排序else if (begin2 >= n){break;}//end2越界,情况3//解决:让end2等于数组最后的下标else if (end2 >= n){end2 = n - 1;}//开始按顺序归并while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}// 归并一部分,拷贝一部分memcpy(a + i, tmp + i, sizeof(int)*(end2 - i + 1));}rangeN *= 2;}free(tmp);tmp = NULL;
}

如果一次性拷贝

{......//修正路线if (end1 >= n){end1 = n - 1;begin2 = n;end2 = n - 1;}else if (begin2 >= n){begin2 = n;end2 = n - 1;}else if (end2 >= n){end2 = n - 1;}......
}

特性总结:

  • 归并的缺点在于需要O(N)的空间复杂度,
  • 归并排序的思考更多的是解决在磁盘中的外排序问题
  • 时间复杂度:O(N*logN)
  • 空间复杂度:O(N)
  • 稳定性:稳定

3.非比较排序

3.1 计数排序

基本思想:
之前学习的排序,无论是希尔排序,还是堆排序,都用的是比较两个数大小的方式进行的排序

而计数排序不是用比较的方法来进行排序的,它利用的是数组下标的计数来进行的排序

请添加图片描述

具体实现方法如下:

算法原理:
现假设有一组0~4的数据需要排序:{ 2,3,3,4,0,3,2,4,3 }

创建一个临时数组temp来依次记录每个数的出现次数

原数组中,

   0出现了1次,就在temp下标为0的位置记录11没有出现,  就在temp下标为1的位置记录02出现了2次,就在temp下标为0的位置记录23出现了4次,就在temp下标为0的位置记录34出现了2次,就在temp下标为0的位置记录2

数组每一个下标位置的值,代表了数列中对应整数出现的次数。

有了这个 “统计结果”,排序就很简单了。
直接遍历数组,输出数组元素的下标值,元素的值是几,就输出几次:

请添加图片描述

这样就能得到一个有序序列了

这就是计数排序的过程,因为他没有进行数与数之间的比较,
所以他的性能甚至快过那些O( log N) 的排序

可以看到上面的排序是一种特殊情况,那如果我们要排序的数组是 9000~9009,那么是不是得浪费前九千多个空间?

又或者是在原数组里面有负数的情况下是不是九不能进行计数排序了?

这就要对现有的算法进行一些小小的升级了

算法升级
例如我们有一组这样的数:9004,9001,9002,9005,9004,9001

这个数组,最大是9005,但最小的数是9001,如果用长度为9005的数组,那么按照上面的方法排序,肯定会太过浪费

事实上我们只需要开辟大小为5的数组即可(最大数 - 最小数 + 1)9005 - 9001 +1 = 5

用下标为0的记录9001,用下标为4的记录9005

请添加图片描述

当然,对于负数也一样可以使用,这里就不一一展示了

性能特点:

  • 稳定性:稳定
  • 时间复杂度:O(n+k)
  • 空间复杂度:O(n+k)
  • 对于数据率不是很大,并且数据比较集中时,计数排序是一个很有效的排序算法

计数排序的局限性:

不能对小数进行排序,只适用于整数

分4步实现

  • 找到数组中的最大最小值
  • 计算范围,开辟临时数组空间
  • 统计相同元素出现次数
  • 根据计数结果将序列依次放回原来的数组中
//计数排序
void CountSort(int* a, int n)
{//确定数组里面的最大最小值int max = a[0], min = a[0];for (int i = 1;i < n;i++){if (a[i] < min)min = a[i];if (a[i] > max)max = a[i];}//范围 = 最大值 - 最小值 + 1//比如从 0 到 9 有10个数int range = max - min + 1;//用calloc开辟range个大小为int的空间,并给每个元素赋值为0int* countA = (int*)calloc(range, sizeof(int));if (countA == NULL){perror("calloc fail");exit(-1);}//统计相同元素出现的次数for (int i = 0;i < n;i++){//a[i] - min 是a[i]下标在countA里面对应的相对位置countA[a[i] - min]++;}//排序,根据计数结果将序列依次放回原来的数组中int k = 0;for (int j = 0;j < range;j++){while (countA[j]--){//j + min 就是数组元素的大小a[k++] = j + min;}}free(countA);
}

排序算法复杂度及稳定性分析

稳定性
请添加图片描述

稳定性的价值:

比如再考试排名的时候,第三名种有三个人的成绩相同,那么如果先交卷的人是第三名的话,就要去再成绩排序的时候保证其稳定性

各种常见排序算法的总结

请添加图片描述

相关文章:

初阶5 排序

本章重点 排序的概念常见排序的算法思想和实现排序算法的复杂度以及稳定性分析 1.排序的概念 排序: 所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。稳定性: 假定在待排序的记录序列中&#xff0…...

备赛蓝桥杯之第十五届职业院校组省赛第二题:分享点滴

提示&#xff1a;本篇文章仅仅是作者自己目前在备赛蓝桥杯中&#xff0c;自己学习与刷题的学习笔记&#xff0c;写的不好&#xff0c;欢迎大家批评与建议 由于个别题目代码量与题目量偏大&#xff0c;请大家自己去蓝桥杯官网【连接高校和企业 - 蓝桥云课】去寻找原题&#xff0…...

qml ColumnLayout详解

1、概述 ColumnLayout 是 QML 中用于在垂直方向上排列子元素的一种布局管理器。它继承自 Item 并提供了简单的布局机制&#xff0c;使得子元素能够按照从上到下的顺序自动排列。ColumnLayout 通常用于创建具有垂直层次结构的用户界面。 2、重要属性 layoutDirection 类型&…...

Qt 5.14.2 学习记录 —— 십팔 对话框

文章目录 1、Qt对话框2、自定义对话框1、代码方式2、图形化方式 3、模态对话框4、QMessageBox5、QColorDialog6、QFileDialog7、QFontDialog8、QInputDialog 1、Qt对话框 Qt的对话框用QDialog类来表示&#xff0c;可以自定义一些类来实现自定义对话框&#xff0c;但需要继承自…...

AI 编程工具—Cursor进阶使用 Rules for AI

AI 编程工具—Cursor进阶使用 Rules for AI 这里配置是给所有的会话和内嵌模式的,你可以理解为是一个全局的配置 下面的代码是之前Cursor 给我们生成的,下面我们开始配置Rules ,来让Cursor生成的代码更加符合我们的编程习惯 def quick_sort(arr):"""使用快…...

SpringBoot 实现动态管理定时任务 Job的动态操作(添加、修改、启停、执行、删除)以及界面展示和具体Job的创建与执行示例

SpringBoot 实现动态管理定时任务 Job的动态操作&#xff08;添加、修改、启停、执行、删除&#xff09;以及界面展示和具体Job的创建与执行示例 关键接口类&#xff1a; CronTaskRegistrar SchedulingRunnable . 添加定时任务注册类&#xff0c;用来增加、删除定时任务 impo…...

FPGA中场战事

2023年10月3日,英特尔宣布由桑德拉里维拉(Sandra Rivera)担任“分拆”后独立运营的可编程事业部首席执行官。 从数据中心和人工智能(DCAI)部门总经理,转身为执掌该业务的CEO,对她取得像AMD掌门人苏姿丰博士类似的成功,无疑抱以厚望。 十年前,英特尔花费167亿美元真金白银…...

_CLASSDEF在C++中的用法详解及示例

_CLASSDEF在C++中的用法详解及示例 _CLASSDEF的定义与使用示例说明代码解析总结在C++编程中,宏(Macro)是一种预处理指令,它允许程序员在编译之前对代码进行文本替换。_CLASSDEF是一个自定义的宏,它提供了一种便捷的方式来定义类及其相关类型。本文将详细介绍_CLASSDEF在C+…...

缓存-Redis-数据结构-redis哪些数据结构是跳表实现的?

在 Redis 中&#xff0c;跳表&#xff08;Skip List&#xff09; 被用于实现 有序集合&#xff08;Sorted Set&#xff09; 数据结构。以下是对此实现的详细解释&#xff1a; Redis中的有序集合&#xff08;Sorted Set&#xff09; 有序集合&#xff08;Sorted Set&#xff0…...

K8S中Service详解(二)

Service类型 Service的资源清单文件&#xff1a; --- kind: Service # 资源类型 apiVersion: v1 # 资源版本 metadata: # 元数据name: service # 资源名称namespace: dev # 命名空间 spec: # 描述selector: # 标签选择器&#xff0c;用于确定当前service代理哪些podapp: ngin…...

鸿蒙模块概念和应用启动相关类(HAP、HAR、HSP、AbilityStage、UIAbility、WindowStage、window)

目录 鸿蒙模块概念 HAP entry feature har shared 使用场景 HAP、HAR、HSP介绍 HAP、HAR、HSP开发 应用的启动 AbilityStage UIAbility WindowStage Window 拉起应用到显示到前台流程 鸿蒙模块概念 HAP hap包是手机安装的最小单元&#xff0c;1个app包含一个或…...

【EXCEL_VBA_实战】多工作薄合并深入理解

工作背景&#xff1a;多个工作薄存在冲突的名称&#xff0c;需快速合并 困难点&#xff1a;工作表移动复制时&#xff0c;若有冲突的名称&#xff0c;会不断弹出对话框待人工确认 思路&#xff1a;利用代码确认弹出的对话框 关键代码&#xff1a;Application.DisplayAlerts …...

Maven的下载安装配置

maven的下载安装配置 maven是什么 Maven 是一个用于 Java 平台的 自动化构建工具&#xff0c;由 Apache 组织提供。它不仅可以用作包管理&#xff0c;还支持项目的开发、打包、测试及部署等一系列行为 Maven的核心功能 项目构建生命周期管理&#xff1a;Maven定义了项目构建…...

网络打印机的搜索与连接(一)

介绍 网络打印机就是可以通过网络连接上的打印机&#xff0c;这类打印机分2种&#xff1a;自身具有互联网接入功能可以分配IP的打印机我们称为网络打印机、另外一种就是被某台电脑连接上去后通过共享的方式共享到网络里面的我们称为共享打印机。现在还有一种可以通过互联网连接…...

高并发压力测试

高并发压力测试 CountDownLatch就是JUC包下的一个工具&#xff0c;整个工具最核心的功能就是计数器。 需要一个并发安全的计数器来操作。CountDownLatch就可以实现。 给CountDownLatch设置一个数值。 每个业务处理完毕之后&#xff0c;执行一次countDown方法&#xff0c;指…...

Python中采用.add_subplot绘制子图的方法简要举例介绍

Python中采用.add_subplot绘制子图的方法简要举例介绍 目录 Python中采用.add_subplot绘制子图的方法简要举例介绍一、Python中绘制子图的方法1.1 add_subplot函数1.2 基本语法&#xff08;1&#xff09;add_subplot的核心语法&#xff08;2&#xff09;add_subplot在中编程中的…...

ipad和macbook同步zotero文献附件失败的解决办法

背景&#xff1a;我所有的文献及其附件pdf都是在台式机&#xff08;windows系统&#xff09;&#xff0c;想要把这些文献同步到云上&#xff0c;然后再从云上同步到平板和其他笔记本电脑比如macbook。文献同步虽已成功&#xff0c;但文献附件都无法打开。 平板报错如下&#xf…...

循环队列(C语言)

从今天开始我会开启一个专栏leetcode每日一题&#xff0c;大家互相交流代码经验&#xff0c;也当作我每天练习的自我回顾。第一天的内容是leetcode622.设计循环队列。 一、题目详细 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#…...

Amazon Redshift实用命令语句

1. 数据库管理相关命令 创建数据库 CREATE DATABASE mydatabase;Amazon Redshift创建数据库命令除了基本形式外&#xff0c;还有以下几种带不同参数的形式&#xff1a; 带OWNER参数 可以指定数据库的所有者&#xff0c;通常是一个数据库用户或角色。 CREATE DATABASE myda…...

音频入门(二):音频数据增强

本文介绍了一些常见的音频数据增强方法&#xff0c;并给出了代码实现。 目录 一、简介 二、代码 1. 安装必要的库 2. 代码 3. 各函数的介绍 4. 使用方法 参考&#xff1a; 一、简介 音频数据增强是机器学习和深度学习领域中用于改善模型性能和泛化能力的技术。 使用数据…...

【Hadoop面试题2025】

文章目录 简单题故障及相应的处理方法中等难度高难度小文件小文件的产生小文件问题的影响小文件治理方案推荐方案 冷文件冷文件的产生冷文件问题的影响冷文件治理方案推荐方案 简单题 一、基础概念类 什么是Hadoop&#xff1f; 答案&#xff1a;Hadoop是一个开源的分布式计算框…...

Unity自学之旅03

Unity自学之旅03 Unity自学之旅03&#x1f4dd; 碰撞体 Collider 基础定义与作用常见类型OnCollisionEnter 事件碰撞触发器 &#x1f917; 总结归纳 Unity自学之旅03 &#x1f4dd; 碰撞体 Collider 基础 定义与作用 定义&#xff1a;碰撞体是游戏中用于检测物体之间碰撞的组…...

STranslate 中文绿色版即时翻译/ OCR 工具 v1.3.1.120

STranslate 是一款功能强大且用户友好的翻译工具&#xff0c;它支持多种语言的即时翻译&#xff0c;提供丰富的翻译功能和便捷的使用体验。STranslate 特别适合需要频繁进行多语言交流的个人用户、商务人士和翻译工作者。 软件功能 1. 即时翻译&#xff1a; 文本翻译&#xff…...

树的存储(c++)

树结构相对线性结构来说就⽐较复杂。存储时&#xff0c;既要保存值域&#xff0c;也要保存结点与结点之间的关系。实际中树有很多种存储⽅式&#xff1a;双亲表⽰法&#xff0c;孩⼦表⽰法、孩⼦双亲表⽰法以及孩⼦兄弟表⽰法等。现阶段&#xff0c;我们只⽤掌握孩⼦表⽰法&…...

JVM面试题解,垃圾回收之“对象存活判断”剖析

一、JVM怎么判断一个类/对象是不是垃圾&#xff1f; 先来说如何判断一个对象是不是垃圾 最常用的就是引用计数法和可达性分析 引用计数法 引用计数法为每个对象维护一个计数器来跟踪有多少个引用指向该对象。每当创建一个新的引用指向某个对象时&#xff0c;计数器加1&…...

【Elasticsearch】 Ingest Pipeline `processors`属性详解

在Elasticsearch中&#xff0c;Ingest Pipeline 的 processors 属性是一个数组&#xff0c;包含一个或多个处理器&#xff08;processors&#xff09;。每个处理器定义了一个数据处理步骤&#xff0c;可以在数据索引之前对数据进行预处理或富化。以下是对 processors 属性中常见…...

Springboot3 自动装配之核心文件:imports文件

注&#xff1a;本文以spring-boot v3.4.1源码为基础&#xff0c;梳理spring-boot应用启动流程、分析自动装配的原理 如果对spring-boot2自动装配有兴趣&#xff0c;可以看看我另一篇文章&#xff1a; Springboot2 自动装配之spring-autoconfigure-metadata.properties和spring…...

Ceisum无人机巡检直播视频投射

接上次的视频投影&#xff0c;Leader告诉我这个视频投影要用在两个地方&#xff0c;一个是我原先写的轨迹回放那里&#xff0c;另一个在无人机起飞后的地图回显&#xff0c;要实时播放无人机拍摄的视频&#xff0c;还要能转镜头&#xff0c;让我把这个也接一下。 我的天&#x…...

【IJCAI】2025 投稿重点记录

【IJCAI】2025 投稿重点记录 写在最前面【IJCAI】2025 投稿重点记录1. 文件说明2. 论文长度要求正式版本的页面扩展 3. 作者信息及匿名性要求4. 摘要5. 附录与补充内容6. 审稿重点与伦理声明7. 参考文献与贡献声明8. 技术要点与补充细节 &#x1f308;你好呀&#xff01;我是 是…...

U3D的.Net学习

Mono&#xff1a;这是 Unity 最初采用的方式&#xff0c;它将 C# 代码编译为中间语言 (IL)&#xff0c;然后在目标平台上使用虚拟机 (VM) 将其转换为本地机器码执行。 IL2CPP&#xff1a;这是一种较新的方法&#xff0c;它会将 C# 代码先编译为 C 代码&#xff0c;再由 C 编译器…...

C++ 二叉搜索树

目录 概念 性能分析 二叉搜索树的插入 二叉树的查找 二叉树的前序遍历 二叉搜索树的删除&#xff08;重点&#xff09; 完整代码 key与value的使用 概念 对于一个二叉搜索树 若它的左子树不为空&#xff0c;则左子树上所有的节点的值都小于等于根节点的值若它的右子树不为空…...

使用HTML5 Canvas 实现呼吸粒子球动画效果的原理

在网页开发领域&#xff0c;动画效果能够极大地提升用户体验&#xff0c;让页面变得更加生动有趣。今天&#xff0c;我们深入剖析一个基于 HTML5 Canvas 的 3D 粒子动画 —— 呼吸粒子球。通过详细解读其代码实现&#xff0c;我们将全面了解如何运用 HTML5 的强大功能构建出如此…...

计算机网络 (56)交互式音频/视频

一、定义与特点 定义&#xff1a;交互式音频/视频是指用户使用互联网和其他人进行实时交互式通信的技术&#xff0c;包括语音、视频图像等多媒体实时通信。 特点&#xff1a; 实时性&#xff1a;音频和视频数据是实时传输和播放的&#xff0c;用户之间可以进行即时的交流。交互…...

Androidstudio 中,project下的.gitignore和module下的.gitignore有什么区别,生效优先级是什么

在 Android Studio 项目中&#xff0c;project 根目录下的 .gitignore 文件和 module 目录下的 .gitignore 文件作用和生效优先级是不同的&#xff0c;理解它们之间的区别非常重要&#xff0c;可以避免不必要的提交和冲突。 1. project 根目录下的 .gitignore&#xff1a; 作…...

三篇物联网漏洞挖掘综述

由于物联网设备存在硬件资源受限、硬件复杂异构&#xff0c; 代码、文档未公开的问题&#xff0c; 物联网设备的漏洞挖掘存在较大的挑战&#xff1a; 硬件资源受限性: 通用动态二进分析技术需要在运行程序外围实施监控分析。由于物联网设备存储资源(存储)的受限性&#xff0c;…...

【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题

本篇博客给大家带来的是01背包问题之动态规划解法技巧. &#x1f40e;文章专栏: 动态规划 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅&#x1f680; 要开心要快乐顺便…...

uniapps使用HTML5的io模块拷贝文件目录

最近在集成sqlite到uniapp的过程中&#xff0c;因为要将sqlite数据库预加载&#xff0c;所以需要使用HTML5的plus.io模块。使用过程中遇到了许多问题&#xff0c;比如文件路径总是解析不到等。尤其是应用私有文档目录’_doc’。 根据官方文档&#xff1a; 为了安全管理应用的…...

Word2Vec如何优化从中间层到输出层的计算?

文章目录 Word2Vec如何优化从中间层到输出层的计算&#xff1f;用负采样优化中间层到输出层的计算负采样方法的关键思想负采样的例子负采样的采样方法 Word2Vec如何优化从中间层到输出层的计算&#xff1f; 重要性&#xff1a;★★ 用负采样优化中间层到输出层的计算 以词汇…...

C#中的语句

C#提供了各式各样的语句&#xff0c;大多数是由C和C发展而来&#xff0c;当然&#xff0c;在C#中做了相应修改。语句和表达式一样&#xff0c;都是C#程序的基本组成部分&#xff0c;在本文我们来一起学习C#语句。 1.语句 语句是构造所有C#程序的过程构造块。在语句中可以声明…...

2.3.1(项目)kv存储——框架梳理(待定)

一、过一遍代码路线&#xff1a; 体会&#xff1a;&#xff08;1&#xff09;接口统一、测试标准统一&#xff0c;软件才会有量产的过程&#xff1b;&#xff08;b&#xff09;多层框架&#xff0c;实现业务部分和网络部分的完全剥离。 实现多层框架&#xff1a; &#xff0…...

【YOLOv10改进[Backbone]】使用ConvNeXtV2替换Backbone

本文将进行在YOLOv10中使用ConvNeXtV2替换Backbone魔改v10的实践,文中含全部代码、详细修改方式。助您轻松理解改进的方法。 目录 一 ConvNeXtV2 二 魔改YOLOv10 1 整体修改 ① 添加python文件 ② 修改ultralytics/nn/tasks.py文件 2 配置文件...

在C#中添加I/O延时和持续时间

在C#中添加I/O延时和持续时间&#xff0c;可以通过以下方法实现。具体来说&#xff0c;延时可以通过Thread.Sleep、Task.Delay等方式来模拟延迟&#xff0c;而持续时间的控制可以通过循环结构来设定持续的时间。在执行I/O操作时&#xff0c;你可以在操作之间添加延时&#xff0…...

VUE之路由Props、replace、编程式路由导航、重定向

目录 1、路由_props的配置 2、路由_replaces属性 3、编程式路由导航 4、路由重定向 1、路由_props的配置 1&#xff09;第一种写法&#xff0c;将路由收到的所有params参数作为props传给路由组件 只能适用于params参数 // 创建一个路由器&#xff0c;并暴露出去// 第一步…...

RabbitMQ的消息可靠性保证

文章目录 1.环境搭建1.common-rabbitmq-starter 配置防止消费者抢消息&#xff08;基础配置&#xff09;2.common-rabbitmq-starter-demo下创建一个生产者一个消费者 2.生产者可靠性1.开启消息超时重试机制2.生产者开启ConfirmCallback消息确认机制1.application.yml2.TestConf…...

MySQL 很重要的库 - 信息字典

在做owasp SQL 注入的时候&#xff0c;有个很重要的库&#xff0c;那就是 信息库: 这个库就是: information_schema; &#xff08;准确的说&#xff0c;数据字典) mysql> show databases; -------------------- | Database | -------------------- | informa…...

使用C#对指定的MYSQL数据库进行备份以及常见问题

最近在开发过程中&#xff0c;需要做个MYSQL数据库的备份&#xff0c;大致总结了一下代码&#xff0c;以及常见的坑 string bakName "database" DateTime.Now.ToString("yyyyMMddHHmmss") ".sql";//备份后的数据库文件名var bakupFilePath &q…...

Appium(四)

一、app页面元素定位 1、通过id定位元素: resrouce-id2、通过ClassName定位&#xff1a;classname3、通过AccessibilityId定位&#xff1a;content-desc4、通过AndroidUiAutomator定位5、通过xpath定位xpath、id、class、accessibility id、android uiautomatorUI AutomatorUI自…...

jvm_threads_live_threads 和 jvm_threads_states_threads 这两个指标之间存在一定的关系,但它们关注的维度不同

jvm_threads_live_threads 和 jvm_threads_states_threads 这两个指标之间存在一定的关系&#xff0c;但它们关注的维度不同。以下是它们的详细关系和区别&#xff1a; 1. jvm_threads_live_threads 含义&#xff1a; 表示当前 JVM 中存活的线程总数&#xff08;即当前活动的线…...

docker 部署.netcore应用优势在什么地方?

目录 1. 环境一致性 2. 简化依赖管理 3. 快速部署与扩展 4. 资源利用率高 5. 版本控制与回滚 6. 安全性 7. 生态系统支持 8. 微服务架构支持 9. 降低成本 10. 开发体验提升 总结 使用 Docker 部署 .NET Core 应用有许多优势&#xff0c;特别是在开发、测试和生产环境…...

SpringBoot开发(一)应用jar包

1. SpringBoot开发 1.1. 目标及简介 1.1.1. 目标 &#xff08;1&#xff09;掌握微服务SpringBoot在实际项目开发中常用的核心技术栈及其在典型业务场景下的应用实战。   &#xff08;2&#xff09;掌握SpringBoot SpringMVC Mybatis在Java Web应用开发过程的技术干货以及…...