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

8.排序(直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序)的模拟实现

1.排序的概念及其运用

1.1排序的概念

  • 排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

  • 稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

  • 内部排序:数据元素全部放在内存中的排序。

  • 外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

1.2 常见的排序算法

image-20230319215844914

2.常见排序算法的实现

2.1插入排序

1.直接插入排序

image-20230319215926363

// 最坏时间复杂度O(N^2) -- 原数组是逆序
// 最好时间复杂度O(N) -- 原数组是顺序有序// 直接插入排序
void InsertSort(int* a, int n)
{// 在[0,end]范围内 插入第 end+1 个数据  并使[0, end+1]范围内的数据有序for (int i = 0; i < n - 1; ++i){// 根据上面的图解来理解a[end] 和 tmp的下标int end = i;int tmp = a[end + 1];// 当end >= 0,那么就继续比较a[end]与tmpwhile (end >= 0){// 将数组排列为一个升序数组if (a[end] > tmp){// 如果前一个数据a[end],大于后一个数据tmp// 直接用end位置的数据覆盖end + 1的数据,保持tmp不发生改变a[end + 1] = a[end];// 迭代--end;}else{break;}}// 当循环结束,end + 1处的数据是旧数据,需要使用tmp更新a[end + 1] = tmp;}
}

打印数组(便于我们来观察排序)

void PrintArray(int* a, int n)
{for (int i = 0; i < n; ++i){printf("%d ", a[i]);}printf("\n");
}

2.希尔排序( 缩小增量排序 )

image-20230319220012509

// 情况二:
// 注:希尔排序的时间复杂度,太过复杂,我们可以默认理解希尔排序的时间复杂度为O(N^1.3),
// 当数据量很大时,是比堆排序O(N*logN)略差的
// 希尔排序的时间复杂度为O(N^1.3)// 这个函数采用的是多组并排排序的方法来实现希尔排序
void ShellSort(int* a, int n)
{// 将间隔为gap的数据分为一组int gap = n;// gap > 1  预排序// gap == 1 直接插入排序// 当while循环结束,说明缩小gap间隙最终为1,数组已经很接近有序了while (gap > 1){// 下面是缩小间隙的两种方法,本文采用第二种// gap = gap / 2;gap = gap / 3 + 1;       // 当for循环结束,gap为n的所有组数据就排列好了// 下面for循环的算法就是,直接插入排序的算法,// 只是改变了a[end]和tmp下标之间的距离for (int i = 0; i < n - gap; ++i){int end = i;int tmp = a[end + gap];// 直到end < 0才可以停止比较while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}
}
// 情况一: 分组进行排序
// 时间复杂度为:O(N^1.3)
void ShellSort(int* a, int n)
{int gap = n;while (gap > 1){//gap = gap / 2;gap = gap / 3 + 1;// 间隔为gap的数据// 当j改变,就是代表一组数据排列完成,将要对下一组数据进行排序for (int j = 0; j < gap; ++j){// 间隔为gap一组排序for (int i = j; i < n - gap; i += gap){int end = i;int tmp = a[end + gap];while (end >= 0){if (a[end] > tmp){a[end + gap] = a[end];end -= gap;}else{break;}}a[end + gap] = tmp;}}}
}

2.2 选择排序

1.直接选择排序

基本思想:

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

直接选择排序:

  • 在元素集合array[i]–array[n-1]中选择关键码最大(小)的数据元素

  • 若它不是这组元素中的最后一个(第一个)元素,则将它与这组元素中的最后一个(第一个)元素交换

  • 在剩余的array[i]–array[n-2](array[i+1]–array[n-1])集合中,重复上述步骤,直到集合剩余1个元素

image-20230319220049930

// 直接选择排序最坏时间复杂度:O(N^2)
// 直接选择排序最好时间复杂度:O(N^2)
void SelectSort(int* a, int n)
{// 初始化begin和end下标int begin = 0, end = n - 1;// 只有begin小于end时,才可以继续while (begin < end){// 选出最小的放begin位置// 选出最大的放end位置// 将标识最大值和最小值的下标都初始化为beginint mini = begin, maxi = begin;// 当for循环结束时,a[mini]为最小值,a[maxi]为最大值,在[begin,end]范围内for (int i = begin + 1; i <= end; ++i){// 如果为真,那么i下标所在的元素就是最大值,所以更改最大值的下标maxi为iif (a[i] > a[maxi]){maxi = i;}if (a[i] < a[mini]){mini = i;}}// 1.现将最小值a[mini]与初始位置的值进行交换Swap(&a[begin], &a[mini]);// 修正一下maxi// 如果初始位置的值是最大值,由于上面进行了交换,所以此时最大值的下标为mini// 因此,将mini赋值给maxiif (maxi == begin)maxi = mini;// 2.将最大值a[maxi]与末尾位置的值进行交换Swap(&a[end], &a[maxi]);// 迭代++begin;--end;}
}

2.堆排序

void AdjustDown(int* a, int n, int parent)
{int minChild = parent * 2 + 1;while (minChild < n){// 找出小的那个孩子if (minChild + 1 < n && a[minChild + 1] > a[minChild]){minChild++;}if (a[minChild] > a[parent]){Swap(&a[minChild], &a[parent]);parent = minChild;minChild = parent * 2 + 1;}else{break;}}
}// O(N*logN)
void HeapSort(int* a, int n)
{// 大思路:选择排序,依次选数,从后往前排// 升序 -- 大堆// 降序 -- 小堆// 建堆 -- 向下调整建堆 - O(N)for (int i = (n - 1 - 1) / 2; i >= 0; --i){AdjustDown(a, n, i);}// 选数 N*logNint i = 1;while (i < n){Swap(&a[0], &a[n - i]);AdjustDown(a, n - i, 0);++i;}
}
  • 关于堆排序请查看作者的另一篇文章,堆排序。

2.3 交换排序

1.冒泡排序

image-20230319220214966

// 交换排序(冒泡排序)
// 冒泡排序最坏情况的时间复杂度:O(N^2)
// 冒泡最好情况的时间复杂度:O(N)
void BubbleSort(int* a, int n)
{// n是数组中元素的个数// 这个for代表趟数for (int j = 0; j < n; ++j){// 每一趟都会将exchange初始化为0// 如果还有a[i - 1] > a[i]存在,那么exchange就会被修改为1// 但是最后一趟时,数组已经是一个有序的数组了,因此exchange不会被修改int exchange = 0;// for代表了一趟中,a[i]与a[i - 1]迭代比较for (int i = 1; i < n - j; ++i){// a[i - 1]是下标较小的元素,a[i]是下标较大的元素// 当这个条件为真,那么交换两个元素的位置if (a[i - 1] > a[i]){Swap(&a[i - 1], &a[i]);exchange = 1;}}if (exchange == 0){break;}}
}

2.快速排序

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

1.hoare版本

image-20230319220240821

void Swap(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}// PartSort函数,是一趟(想要利用上述的方法将这个数组的元素排序,还需要很多趟,具体看后续的解释)
// 返回left和right相遇节点的下标
int PartSort(int* a, int left, int right)
{// 将左侧的下标定义为keyi下标int keyi = left;// 当left等于right说明两个人相遇了,那么就停止循环while (left < right){// Right需要找比a[keyi]小的数// 因此,如果a[right] >= a[keyi]为真,那么就继续循环// 注意:在循环的过程中一定要保证left < right,否则就没有意义了while (left < right && a[right] >= a[keyi]){--right;}// Lift需要找比a[keyi]大的数while (left < right && a[left] <= a[keyi]){++left;}// 如果此时left < right为真,那么就交换a[left]和a[right]if (left < right)Swap(&a[left], &a[right]);}// 此时,left和right都是相遇节点的下标,// 使用left赋值给meetiint meeti = left;// 将相遇节点的数据与keyi下标的数据进行交换Swap(&a[meeti], &a[keyi]);return meeti;
}

image-20230319220322585

// 快速排序
void QuickSort(int* a, int begin, int end)
{// 必须满足begin小于end// 否则,就返回if (begin >= end){return;}// 先使用PartSort()函数对[begin,end]区间的数进行一趟排序// PartSort()的返回值是meeti,也就是相遇节点的下标,将其存放到keyiint keyi = PartSort(a, begin, end);// 以keyi为分割点,将[begin,end]区间分割为下面两个区间// [begin, keyi-1] keyi [keyi+1, end]// 左区间递归,和右区间递归QuickSort(a, begin, keyi - 1);QuickSort(a, keyi+1, end);
}
快速排序的优化

image-20230319220354572

// 优化之后的代码// 三数取中
int GetMidIndex(int* a, int left, int right) 
{// 数组中间的数的下标就是midint mid = left + (right - left) / 2;if (a[left] < a[mid]){// 此时a[mid]已经大于a[left],那么只要满足a[mid] < a[right],就返回a[mid]的下标// 满足a[left] > a[right],也就是a[mid]>a[left] > a[right],就返回a[left]的下标// 都不满足,也就是a[right]<a[left]<a[mid],就返回a[right]的下标if (a[mid] < a[right]){return mid;}else if (a[left] > a[right]){return left;}else{return right;}}else // a[left] >= a[mid]{if (a[mid] > a[right]){return mid;}else if (a[left] < a[right]){return left;}else{return right;}}
}// [left, right] -- O(N)
// hoare
// PartSort1函数,是一趟(单趟排序)
int PartSort1(int* a, int left, int right) 
{// 三数取中,得到left,right,left + (right - left) / 2中,中间大的哪个数int mid = GetMidIndex(a, left, right);// 此处的mid就是指中间大的哪个数的下标//printf("[%d,%d]-%d\n", left, right, mid);// 将中间大的数,放在数组的最左侧Swap(&a[left], &a[mid]);// keyi依旧是最左侧的数的下标(继承优化前的代码,不需要做出改动)int keyi = left;while (left < right){// R找小while (left < right && a[right] >= a[keyi]){--right;}// L找大while (left < right && a[left] <= a[keyi]){++left;}if (left < right)Swap(&a[left], &a[right]);}int meeti = left;Swap(&a[meeti], &a[keyi]);return meeti;
}// 快速排序函数
void QuickSort(int* a, int begin, int end)   // 分区间递归
{// 必须保证begin >= end为假,才可以继续迭代if (begin >= end){return;}// 8的取值,参考经验,8比较合适// 当[begin,end]区间的元素小于等于8时,这个时候再分小区间,后三层小区间有很多个// 为了减小栈的开销,当end - begin <= 8为真时,采用直接插入排序来将数组进行排序(此时的数组已经很接近有序了,因此使用直接插入排序,并不会降低太多的效率)if (end - begin <= 8) {// 小区间优化,最后三层用直接插入排序InsertSort(a + begin, end - begin + 1);}else{// 先使用PartSort()函数对[begin,end]区间的数进行一趟排序// PartSort()的返回值是meeti,也就是相遇节点的下标,将其存放到keyiint keyi = PartSort1(a, begin, end);// 以keyi为分割点,将[begin,end]区间分割为下面两个区间// [begin, keyi-1] keyi [keyi+1, end]// 迭代左区间// 迭代右区间QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}
}
2.挖坑法(重要)

image-20230319220421603

// 三数取中
int GetMidIndex(int* a, int left, int right) 
{int mid = left + (right - left) / 2;if (a[left] < a[mid]){if (a[mid] < a[right]){return mid;}else if (a[left] > a[right]){return left;}else{return right;}}else // a[left] >= a[mid]{if (a[mid] > a[right]){return mid;}else if (a[left] < a[right]){return left;}else{return right;}}
}// 挖坑法
int PartSort2(int* a, int left, int right)
{// 三数取中int mid = GetMidIndex(a, left, right);Swap(&a[left], &a[mid]);// 将key值初始化为a[left]// 将坑位的下标hole初始化为leftint key = a[left];int hole = left;while (left < right){// 右边找小,填到左边坑while (left < right && a[right] >= key){--right;}a[hole] = a[right];// 此时right对应的下标成为新的坑位hole = right;// 左边找大,填到右边坑while (left < right && a[left] <= key){++left;}a[hole] = a[left];hole = left;}// 当left和right相遇,将key值放入这个坑位(最后的这个坑位)a[hole] = key;return hole;
}// [begin, end]
void QuickSort(int* a, int begin, int end)   // 分区间递归
{if (begin >= end){return;}if (end - begin <= 8) // 8的取值,参考经验,8比较合适{InsertSort(a + begin, end - begin + 1);// 小区间优化,最后三层用插入排序}else{int keyi = PartSort2(a, begin, end);//[begin, keyi-1] keyi [keyi+1, end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}
}
3.前后指针法
  • 本质就是cur指向的值小于key,prev指向的值大于key,那么交换cur和prev所指向的值

image-20230319220445586

// 三数取中
int GetMidIndex(int* a, int left, int right) 
{int mid = left + (right - left) / 2;if (a[left] < a[mid]){if (a[mid] < a[right]){return mid;}else if (a[left] > a[right]){return left;}else{return right;}}else // a[left] >= a[mid]{if (a[mid] > a[right]){return mid;}else if (a[left] < a[right]){return left;}else{return right;}}
}// 前后指针法
int PartSort3(int* a, int left, int right)
{// 三数取中int mid = GetMidIndex(a, left, right);Swap(&a[left], &a[mid]);int keyi = left;int prev = left;int cur = left + 1;while (cur <= right){// 找小if (a[cur] < a[keyi] && ++prev != cur)Swap(&a[cur], &a[prev]);++cur;}Swap(&a[keyi], &a[prev]);return prev;
}// [begin, end]
void QuickSort(int* a, int begin, int end)   // 分区间递归
{if (begin >= end){return;}if (end - begin <= 8) // 8的取值,参考经验,8比较合适{InsertSort(a + begin, end - begin + 1);// 小区间优化,最后三层用插入排序}else{int keyi = PartSort3(a, begin, end);//[begin, keyi-1] keyi [keyi+1, end]QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}
}

3.快速排序(非递归的方法)

image-20230319220509273

void QuickSortNonR(int* a, int begin, int end)
{// 栈结构对象在堆上面开辟空间,不用担心栈溢出ST st;  // 初始化栈StackInit(&st);// 将区间[begin,end]的左右断点存储到栈对象中StackPush(&st, begin);StackPush(&st, end);// 直到栈为空,循环结束(意味着所有的小区间都已经排序完毕了)while (!StackEmpty(&st)){// 因为压栈的时候是先压入的左端点,再压入右端点(都是下标)// 所以,从栈顶拿出数据时,是先拿出右端点,再拿出左端点(都是下标)int right = StackTop(&st);StackPop(&st);int left = StackTop(&st);StackPop(&st);/*if (left >= right)       // 在取出时,判断区间是否满足排序要求{continue;}*/// 根据拿出的区间断点,对这个区间的数据进行一趟排序int keyi = PartSort3(a, left, right);// 排序完之后,得到下标keyi,根据下标keyi将之前的区间重新分为两个新区间// 再将两个新区间的左右端点入栈,就可以重复上述的操作,完成所有区间的排序// [left, keyi-1] keyi [keyi+1,right]// 在存入时,判断区间是否满足存入要求,避免无效存储,和取出判断if (keyi + 1 < right)     {StackPush(&st, keyi + 1);StackPush(&st, right);}// 在存入时,判断区间是否满足存入要求,避免无效存储,和取出判断if (left < keyi- 1)     {StackPush(&st, left);StackPush(&st, keyi - 1);}}// 最后,销毁栈对象开辟的空间,防止内存泄漏StackDestroy(&st);
}

2.4 归并排序

基本思想:

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and

Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有

序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:

image-20230319220539106

归并排序(递归的方法

image-20230319220600395

归并排序(递归的方法)

#define _CRT_SECURE_NO_WARNINGS#include<stdio.h>// 归并排序(递归的方法)
// 函数_MergeSort是函数MergeSort的一部分
void _MergeSort(int* a, int begin, int end, int* tmp)
{// 必须保证begin >= end为假,否则就直接返回if (begin >= end)return;// 取数组的中间下标,将数组分为两个区间int mid = (end + begin) / 2;// [begin, mid] [mid+1, end]// 左区间迭代和右区间迭代_MergeSort(a, begin, mid, tmp);_MergeSort(a, mid + 1, end, tmp);// 迭代完之后,此时有无数个被分裂的小区间,每个区间只有一个数// 归并 取两个区间中小的数值尾插到tmp中(tmp是一个临时数组,临时存放这些归并的数据的)// 注:因为左右区间是迭代的,所以begin,mid,end的大小对应相应的迭代,当回到迭代最初的地方// 那么[begin, mid] [mid+1, end]这两个区间的数已经是有序的了// [begin, mid] [mid+1, end]int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;// 两个区间的数归并时,必须满足 begin1 <= end1 && begin2 <= end2int i = begin;while (begin1 <= end1 && begin2 <= end2){// 取两个区间中较小的数尾插到tmp中if (a[begin1] <= a[begin2]){// 后置++,先使用,后++tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}// 如果区间2的数尾插完了,但是区间1的数没有尾插完,那么这里将区间一剩余的数尾插到tmp中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");return;}// void _MergeSort(int* a, int begin, int end, int* tmp)_MergeSort(a, 0, n - 1, tmp);free(tmp);tmp = NULL;
}void PrintArray(int* a, int n)
{for (int i = 0; i < n; ++i){printf("%d ", a[i]);}printf("\n");
}void TestMergeSort()
{int a[] = { 100, 56, 25, 86, 99, 72, 66 };int n = sizeof(a) / sizeof(int);MergeSort(a, n);PrintArray(a, n);
}int main()
{TestMergeSort();return 0;
}
memcpy()的用法

在C语言中,memcpy() 函数用于在内存之间复制一定数量的字节。它的原型如下:

void *memcpy(void *dest, const void *src, size_t n);
  • dest 是目标内存区域的指针,指向要复制到的位置。
  • src 是源内存区域的指针,指向要复制的数据的起始位置。
  • n 是要复制的字节数。

memcpy() 函数将源内存区域中的数据复制到目标内存区域中。它返回目标内存区域的起始位置(即 dest 指针),这使得可以将 memcpy() 作为一个表达式的一部分来使用。

以下是一个示例代码,演示了如何使用 memcpy() 函数复制内存中的数据:

#include <stdio.h>
#include <string.h>int main() {char src[] = "Hello, world!";char dest[20];// 将 src 中的数据复制到 dest 中memcpy(dest, src, strlen(src) + 1);// 打印复制后的字符串printf("Copied string: %s\n", dest);return 0;
}

在这个示例中,我们将字符串 "Hello, world!" 从源内存区域 src 复制到目标内存区域 dest 中,然后打印出复制后的字符串。

归并排序(非递归的方式)

image-20230319220643122

image-20230319220715925

void MergeSortNonR(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int)*n);if (tmp == NULL){perror("malloc fail");return;}int gap = 1;while (gap < n){// 首次循环时,每个区间只有一个数,此时gap=1// 当归并一次之后,每个区间就有两个数,那时就将gap扩大两倍// gap个数据  gap个数据归并// gap每改变一次,进行一次for循环for (int j = 0; j < n; j += 2 * gap){// 归并两个区间 取较小的值尾插到tmp// j为区间一的区间为[j,j + gap - 1]// 区间二的区间为[j + gap,j + 2 * gap - 1]int begin1 = j, end1 = j + gap - 1;int begin2 = j + gap, end2 = j + 2 * gap - 1;// 当归并到最后两组的数据,并且第一组就完全越界了// 那么不需要进行归并,直接跳出循环就可以if (end1 >= n){printf("[%d,%d]", begin1, n-1);break;}// 第二组全部越界,直接跳出循环就可以// 此时的第一组数据必然是有序的if (begin2 >= n){printf("[%d,%d]", begin1, end1);break;}// 第二组部分越界if (end2 >= n){// 修正一下end2,继续归并(第二组最后一个数的下标,最大为n-1)end2 = n - 1;}printf("[%d,%d][%d,%d] ", begin1, end1, begin2, end2);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, (end2-j+1)*sizeof(int));}// 扩大区间范围gap *= 2;printf("\n");}free(tmp);tmp = NULL;
}

相关文章:

8.排序(直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序)的模拟实现

1.排序的概念及其运用 1.1排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录…...

(详解)python调用另一个.py文件中的类和函数或直接运行另一个.py文件

一、同一文件夹下的调用 1.调用函数 A.py文件如下&#xff1a; def add(x,y):print(和为&#xff1a;%d%(xy))在B.py文件中调用A.py的add函数如下&#xff1a; import A A.add(1,2)或 from A import add add(1,2)2.调用类 A.py文件如下&#xff1a; class Add:def __ini…...

每日一题:修改后的最大二进制字符串

给你一个二进制字符串 binary &#xff0c;它仅有 0 或者 1 组成。你可以使用下面的操作任意次对它进行修改&#xff1a; 操作 1 &#xff1a;如果二进制串包含子字符串 "00" &#xff0c;你可以用 "10" 将其替换。 比方说&#xff0c; "00010"…...

Redis 5种数据结构常用命令

文章目录 1 字符串2 哈希3 列表4 集合5 有序集合 1 字符串 命令描述set key value设置指定key的值为valueget key获取指定key的值del key [key …]删除一个或多个keymset key value [key value …]设置多个key的值mget key [key …]获取一个或多个key的值incr key将key中储存的…...

23、区间和

区间和 题目描述 假定有一个无限长的数轴&#xff0c;数轴上每个坐标上的数都是0。 现在&#xff0c;我们首先进行 n 次操作&#xff0c;每次操作将某一位置x上的数加c。 接下来&#xff0c;进行 m 次询问&#xff0c;每个询问包含两个整数l和r&#xff0c;你需要求出在区间…...

Python零基础从小白打怪升级中~~~~~~~文件和文件夹的操作 (1)

第七节&#xff1a;文件和文件夹的操作 一、IO流&#xff08;Stream&#xff09; 通过“流”的形式允许计算机程序使用相同的方式来访问不同的输入/输出源。stream是从起源&#xff08;source&#xff09;到接收的&#xff08;sink&#xff09;的有序数据。我们这里把输入/输…...

Qt plugin 开发UI界面插件

目录 1.创建接口 2.创建插件 3.创建插件界面 4.插件实现 5.创建应用工程 6.应用插件 1.创建接口 打开QtCreater&#xff0c;点击左上角“文件”->新建文件或项目&#xff0c;在弹窗中选择C/CHeader File。 输入文件名&#xff0c;选好路径&#xff08;可自行设置名称…...

Android查看SO库的依赖

➜ bin pwd /Users/xxx/Library/Android/sdk/ndk/21.1.6352462/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin ➜ bin ./aarch64-linux-android-readelf -d /Download/libxxx.so 0x0000000000000001 (NEEDED) Shared library: [liblog.so]0x…...

麒麟KOS删除鼠标右键新建菜单里不需要的选项

原文链接&#xff1a;麒麟KOS删除鼠标右键新建菜单里不需要的选项 Hello&#xff0c;大家好啊&#xff01;在日常使用麒麟KOS操作系统时&#xff0c;我们可能会发现鼠标右键新建菜单里包含了一些不常用或者不需要的选项。这不仅影响我们的使用效率&#xff0c;也让菜单显得杂乱…...

DPDK系列之四十二DPDK应用网络编程UDP编程

一、UDP编程 UDP编程的应用和TCP编程的应用同样非常广泛&#xff0c;如果说真得想使用UDP编程&#xff0c;一般情况下还真得不至于运用DPDK这种重量级的框架。但一个框架的优秀与否&#xff0c;不仅仅在于自身的整体设计优秀&#xff0c;更重要的在于其对应用的支持更完善。 正…...

金三银四面试题(十九):MySQL中的锁

在MySQL中&#xff0c;锁是非常重要的&#xff0c;特别是在多用户并发访问数据库的环境中&#xff0c;因此也是面试中常问的话题。 请说说数据库的锁&#xff1f; 关于MySQL 的锁机制&#xff0c;可能会问很多问题&#xff0c;不过这也得看面试官在这方面的知识储备。 MySQL …...

【JavaScript】原型链/作用域/this指针/闭包

1.原型链 参考资料&#xff1a;Annotated ES5 ECMAScript起初并不支持如C、Smalltalk 或 Java 中“类”的形式创建对象&#xff0c;而是通过字面量表示法或者构造函数创建对象。每个构造函数都是一个具有名为“prototype”的属性的函数&#xff0c;该属性用于实现基于原型的继…...

Python的MATLAB使用

Python和MATLAB是两种不同的编程语言&#xff0c;它们各自拥有不同的生态系统和库。然而&#xff0c;你可以在Python中使用一些方法来实现与MATLAB类似的功能。以下是一些方法和库&#xff0c;可以帮助你在Python中实现MATLAB风格的编程&#xff1a; 1. NumPy: NumPy是Python中…...

文件输入/输出流(I/O)

文章目录 前言一、文件输入\输出流是什么&#xff1f;二、使用方法 1.FileInputStream与FileOutputStream类2.FileReader与FileWriter类总结 前言 对于文章I/O(输入/输出流的概述)&#xff0c;有了下文。这篇文章将具体详细展述如何向磁盘文件中输入数据&#xff0c;或者读取磁…...

docker,schedule job和environment variables三者的含义与区别

这三个概念在软件开发和部署中扮演着不同的角色&#xff1a; Docker一般长这样&#xff1a;superlifestyle/sscp-api Schedule Job一般长这样&#xff1a;recorrect_ocr_receipt_status 、Sync2D365 Environment Variables一般长这样&#xff1a;D365_BATCH_OPERATION_SIZE ima…...

90天玩转Python—16—基础知识篇:面向对象知识详解

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

python 标准库之openpyxl的常规操作

目录 openpyxl&#xff08;Excel文件处理模块&#xff09; 读sheet 读sheet中单元格 合并单元格 openpyxl模块基本用法 安装方法 基本使用 读取Excel文档 &#xff08;一&#xff09;获取工作表 &#xff08;二&#xff09;获取单元格 &#xff08;三&#xff09;获取…...

90天玩转Python—12—基础知识篇:Python自动化操作Email:发送邮件、收邮件与邮箱客户端操作全解析

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…...

利用lidar_align来进行lidar和imu标定

文章目录 下载并安装lidar_align安装nlopt迁移NLOPTConfig.cmake修改loader.cpp文件编译并运行 下载并安装lidar_align mkdir -p lidar_align/src cd lidar_align/src git clone https://github.com/ethz-asl/lidar_align.git安装nlopt git clone http://github.com/steven…...

牛客NC93 设计LRU缓存结构【hard 链表,Map Java】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/5dfded165916435d9defb053c63f1e84 思路 双向链表map最新的数据放头结点&#xff0c;尾节点放最老的数据&#xff0c;没次移除尾巴节点本地考察链表的新增&#xff0c;删除&#xff0c;移动节点参考答案Java im…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

yaml读取写入常见错误 (‘cannot represent an object‘, 117)

错误一&#xff1a;yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因&#xff0c;后面把yaml.safe_dump直接替换成yaml.dump&#xff0c;确实能保存&#xff0c;但出现乱码&#xff1a; 放弃yaml.dump&#xff0c;又切…...

UE5 音效系统

一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类&#xff0c;将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix&#xff0c;将上述三个类翻入其中&#xff0c;通过它管理每个音乐…...