常见排序算法详解

目录

排序的相关概念

排序:

稳定性:

内部排序:                                                                        

外部排序:

常见的排序:

常见排序算法的实现

插入排序:

基本思想:

直接插入排序:

希尔排序(缩小增量排序):

选择排序:

基本思想:

直接选择排序:

堆排序:

交换排序:

基本思想:

冒泡排序:

快速排序:

Hoare版本:

挖坑法:

前后指针法:

快排递归优化:

Hoare版本(优化):

挖坑法(优化):

前后指针(优化):

非递归快排:

归并排序:

基本思想:

递归版本:

非递归版本:

计数排序:

基本思想:

总结

排序的相关概念

排序:

所谓排序,就是使用一定的方法使一段可排序的序列变得有一定的顺序(递增或递减)。

稳定性:

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

内部排序:                                                                        

数据元素全部放在内存中进行排序

外部排序:

数据元素太多无法同时全部放进内存中进行排序。因此,需要将待排序的数据存储在外存(磁盘)上,排序时再把数据一部分一部分地调入内存中进行排序,在排序过程中需要多次进行内存和外存之间地交换。这种排序方法就称作外部排序。

常见的排序:

常见排序算法的实现

插入排序:

基本思想:

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

日常生活中玩扑克牌拼牌时就用到了插入排序。

直接插入排序:

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

排序过程如下图所示:

代码如下:

void InsertSort(int* a, int n)
{assert(a);int i = 0, j = 0;for (i = 1; i < n; i++)//从第二个元素开始,依次与前边的元素比较{int tem = a[i];j = i - 1;while (j >= 0){if (a[j] > tem){a[j + 1] = a[j];}else{break;}j--;}a[j + 1] = tem;}
}

特性总结:

1. 元素集合越接近有序,直接插入排序算法的时间效率越高
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:稳定

希尔排序(缩小增量排序):

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

排序过程如下:

代码如下:

void ShellSort(int* a, int n)
{assert(a);int gap = n;while (gap > 1){gap /= 2;//一组一组排序/*int i = 0;for (i = 0; i < gap; i++){int j = 0;for (j = i; j < n - gap; j += gap)//排一组{int front = j;int back = j + gap;int tem = a[back];//记录back位置原始数据while (front >= 0){if (tem < a[front]){a[back] = a[front];front -= gap;back -= gap;}else{break;}}a[front + gap] = tem;}}*///多组同时排序int j = 0;for (j = 0; j < n - gap; j ++)//多组同时排{int front = j;int back = j + gap;int tem = a[back];//记录back位置原始数据while (front >= 0){if (tem < a[front]){a[back] = a[front];front -= gap;back -= gap;}else{break;}}a[front + gap] = tem;}}}

特性总结:

1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap = 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。
3. 时间复杂度:希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,但有一个大致的范围O(N^1.3)~O(N^2)

4.空间复杂度:O(1)

选择排序:

基本思想:

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

直接选择排序:

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

排序过程如下:

代码如下:

void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}void SelectSort(int* a, int n)
{assert(a);//每次选最小的放前边//int i = 0, j = 0;//int mini = 0;//最小数的下标//for (j = 0; j < n; j++)//{//	mini = j;//	for (i = j + 1; i < n; i++)//	{//		if (a[i] < a[mini])//		{//			mini = i;//		}//	}//	swap(&a[mini], &a[j]);//}//优化--一次选出区间中最大的和最小的,分别插入头部和尾部int begin = 0, end = n - 1;while (begin < end){int maxi = end, mini = begin;//最大最小值的下标int i = begin;for (; i <= end; i++){if (a[i] < a[mini]){mini = i;}if (a[i] > a[maxi]){maxi = i;}}swap(&a[begin], &a[mini]);if (maxi == begin)//防止原begin位置是最大值,被换到mini位置{maxi = mini;}swap(&a[end], &a[maxi]);begin++;end--;}
}

特性总结:

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

堆排序:

堆排序即利用堆的思想来进行排序,思路如下:
1. 建堆
升序:建大堆
降序:建小堆
2. 利用堆删除思想来进行排序
因为堆顶元素一定是最大值(或最小值)每次把堆顶元素与最后一个元素交换,然后把数组尾指针向前移动1,再对新的堆顶元素进行向下调整,重复上述操作,直至数组尾指针指向第一个元素,此时的数组中的数据就是一个有序的序列。

代码如下:

void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}//向下调整(建大堆)
void HeapDown(int* a, int parent, int n)
{assert(a);int child = parent * 2 + 1;//左孩子while (child < n){if (child+1 < n && a[child] < a[child + 1])//找到大的{child += 1;}if (a[child] > a[parent])//大的孩子取代父亲{swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}//堆排序
void HeapSort(int* a, int n)
{assert(a);int parent = (n - 1 - 1) / 2;//建大堆for (parent; parent >= 0; parent--){HeapDown(a, parent, n);}//排序int end = n - 1;while (end >= 0){swap(&a[0], &a[end]);//把最大的放最后,从根向下调整HeapDown(a, 0, end);//从根向下调整end--;}}

特性总结:

1. 堆排序使用堆来选数,效率就高了很多。
2. 时间复杂度:O(N*logN)
3. 空间复杂度:O(1)
4. 稳定性:不稳定

交换排序:

基本思想:

根据序列中两个元素值的比较结果来决定是否交换这两个元素在序列中的位置,进而达到将值较大的元素向序列的尾部移动,值较小的元素向序列的前部移动的目的。

冒泡排序:

两两元素相比,前一个比后一个大就交换,直到将最大的元素交换到末尾位置,这是第一趟排序,第二趟找出第二大的语速放在倒数第二个位置……进行n-1趟排序后,全部数据就是有序的了。

排序动图如下:

代码如下:

void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}//冒泡排序
void BubbleSort(int* a, int n)
{assert(a);int i = 0, j = 0;for (i = 0; i < n - 1; i++){int flag = 0;//标记是否进行过交换for (j = 1; j < n - i; j++){if (a[j-1] > a[j])//每次相邻两个交换{/*int k = a[i];a[i] = a[j];a[j] = k;*/swap(&a[j-1], &a[j]);flag++;}}if (flag == 0){break;}}
}

特性总结:

1. 冒泡排序是一种非常容易理解的排序
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:稳定

快速排序:

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

Hoare版本:

1、选最左边作key,右边先走找到比key小的值

2、左边后走找到大于key的值

3、然后交换left和right的值

4、一直循环重复上述1 2 3步

5、两者相遇时的位置,与最左边选定的key值交换(因为是让右边先走,保证了最后相遇时,该位置的值一定是小于key的)

排序过程如下:

代码如下:

void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}//Hoare
int PartSort1(int* a, int left, int right)
{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[keyi], &a[left]);//因为是右边先开始循环,则当left=right时,a[left]一定小于a[keyi]return left;
}void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort1(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}
挖坑法:

创建变量key储存最左边值,以最左边为第一个坑位,不断填充坑位,并不断改变坑位的位置,直至左右指针相遇,此时为最后一个坑位,再把key填入。

代码入下:

//挖坑法
int PartSort2(int* a, int left, int right)
{int key = a[left];int hold = left;//坑位while (left < right){while (left < right && a[right] >= key){right--;}a[hold] = a[right];hold = right;//更新坑位while (left < right && a[left] <= key){left++;}a[hold] = a[left];hold = left;//更新坑位}a[left] = key;return left;
}void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort2(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}
前后指针法:

代码入下:

void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}//前后指针
int PartSort3(int* a, int left, int right)
{int keyi = left;int prev = left;int cur = left + 1;//cur找比a[keti]小的就和prev后一个交换位置while (cur <= right){if (a[cur] < a[keyi]){swap(&a[++prev], &a[cur]);}cur++;}swap(&a[prev], &a[keyi]);return prev;
}void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}int keyi = PartSort3(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);
}
快排递归优化:

1.三数取中:

快速排序对于数据是敏感的,如果这个序列是非常无序,杂乱无章的,那么快速排序的效率是非常高的,可是如果数列有序,时间复杂度就会从O(N*logN)变为O(N^2),相当于冒泡排序了。若每趟排序所选的key都正好是该序列的中间值,即单趟排序结束后key位于序列正中间,那么快速排序的时间复杂度就是O(NlogN),但是这是理想情况,当我们面对一组极端情况下的序列,就是有序的数组,选择左边作为key值的话,那么就会退化为O(N^2)的复杂度,所以此时我们选择首位置,尾位置,中间位置的数分别作为三数,选出值大小在中间的数,放到最左边,这样选key还是从左边开始,这样优化后,就不会出现选到最大值或最小值的极端情况了。

2.小区间优化:

随着递归深度的增加,递归次数以每层2倍的速度增加,这对效率有着很大的影响,当待排序序列的长度分割到一定大小后,继续分割的效率比插入排序要差,此时可以使用插排而不是快排。

我们可以当划分区间长度小于10的时候,用插入排序对剩下的数进行排序

Hoare版本(优化):
void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}//三数取中
int GetMid(int* a, int left, int right)
{int mid = (left + right) / 2;if (a[left] > a[mid]){if (a[mid] > a[right]){return mid;}else//a[mid]<a[right]{if (a[left] > a[right]){return right;}else{return left;}}}else//a[left]<a[mid] {if (a[left] > a[right]){return left;}else//a[left]<a[right]{if (a[mid] > a[right]){return right;}else{return mid;}}}
}int PartSort1(int* a, int left, int right)
{int mid = GetMid(a, left, right);//三数取中swap(&a[mid], &a[left]);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[keyi], &a[left]);//因为是右边先开始循环,则当left=right时,a[left]一定小于a[keyi]return left;
}void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}if (end - begin + 1 > 10)//小区间优化{int keyi = PartSort1(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}else{InsertSort(a + begin, end - begin + 1);//调用直接插入排序}}
挖坑法(优化):
void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}//三数取中
int GetMid(int* a, int left, int right)
{int mid = (left + right) / 2;if (a[left] > a[mid]){if (a[mid] > a[right]){return mid;}else//a[mid]<a[right]{if (a[left] > a[right]){return right;}else{return left;}}}else//a[left]<a[mid] {if (a[left] > a[right]){return left;}else//a[left]<a[right]{if (a[mid] > a[right]){return right;}else{return mid;}}}
}//挖坑法
int PartSort2(int* a, int left, int right)
{int mid = GetMid(a, left, right);swap(&a[mid], &a[left]);int key = a[left];int hold = left;//坑位while (left < right){while (left < right && a[right] >= key){right--;}a[hold] = a[right];hold = right;//更新坑位while (left < right && a[left] <= key){left++;}a[hold] = a[left];hold = left;//更新坑位}a[left] = key;return left;
}void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}if (end - begin + 1 > 10)//小区间优化{int keyi = PartSort2(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}else{InsertSort(a + begin, end - begin + 1);//调用直接插入排序}}
前后指针(优化):
void swap(int* p1, int* p2)//交换函数
{int k = *p1;*p1 = *p2;*p2 = k;
}int PartSort3(int* a, int left, int right)
{int keyi = left;int prev = left;int cur = left + 1;//cur找比a[keti]小的就和prev后一个交换位置while (cur <= right){if (a[cur] < a[keyi]){swap(&a[++prev], &a[cur]);}cur++;}swap(&a[prev], &a[keyi]);return prev;
}void QuickSort(int* a, int begin, int end)
{if (begin >= end){return;}if (end - begin + 1 > 10)//小区间优化{int keyi = PartSort3(a, begin, end);QuickSort(a, begin, keyi - 1);QuickSort(a, keyi + 1, end);}else{InsertSort(a + begin, end - begin + 1);//直接调用插入排序}}
非递归快排:

当数据量较大时,一直递归调用就会一直开辟栈帧,增加栈的消耗,因此我们可以人工创建一个栈结构,代替递归调用开辟新的栈帧。

关于栈我在栈和队列详解中有详细介绍,在这里就不再过多介绍。

具体思路如下:

1. 申请一个栈,将整个数组的起始位置和终点位置入栈,起始位置先进栈。

2. 利用栈的特性(后进先出),末位置后进栈,所以末位置先出栈。 定义right、left接收的靠近栈顶的两个元素,作为排序序列的始末位置。

3. 对数组进行一次单趟排序,返回一个下标keyi。

4. 此时待排序列被分为[left,keyi-1],keyi,[keyi+1,right]三段,再把左右两边区间的始末位置入栈(若该区间合法),要求区间起始位置先进栈。

5. 重复2、3、4操作直至栈内为空。

代码如下:

//快速排序(非递归)
void QuickSortNonr(int* a, int n)
{ST st;STInit(&st);//栈储存[0,n-1]区间左右下标,先入右下标,后入左下标STPush(&st, n - 1);STPush(&st, 0);while (!STEmpty(&st)){int left = STTop(&st);STPop(&st);int right = STTop(&st);STPop(&st);int keyi = PartSort3(a, left, right);//[left,right]区间分为[left,keyi-1],keyi,[keyi+1,right]if (keyi + 1 < right)//入[keyi+1,right]区间下标{STPush(&st, right);STPush(&st, keyi + 1);}if (keyi - 1 > left)//入[left,keyi-1]区间下标{STPush(&st, keyi - 1);STPush(&st, left);}}STDestroy(&st);
}

特性总结:

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

归并排序:

基本思想:

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

递归版本:

void MerSort(int* a, int* tem, int left, int right)
{if (left >= right){return;}//递归划分区间int mid = (left + right) / 2;MerSort(a, tem, left, mid);MerSort(a, tem, mid + 1, right);//归并到tem数组int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int index = begin1;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tem[index++] = a[begin1++];}else{tem[index++] = a[begin2++];}}while (begin1 <= end1){tem[index++] = a[begin1++];}while (begin2 <= end2){tem[index++] = a[begin2++];}//拷贝回原数组---因为每次都要从原数组中归并到tem数组中,因此每次归并完后都要拷贝回原数组memcpy(a + left, tem + left, sizeof(int) * (right - left + 1));
}
//归并排序
void MergeSort(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");exit(-1);}MerSort(a, tmp, 0, n - 1);free(tmp);
}

非递归版本:

与快排类似,当数据量较大时,一直递归调用会增加栈的消耗,因此我们可以考虑改非递归的方法实现。

归并改非递归时,可以定义一个gap作为每次归并的区间长度,一趟归并后再把gap乘以2,作为新的归并区间长度,继续归并,直至全部归并完成。其关键在于对边界的控制:

代码如下:

//归并排序(非递归)
void MergeSortNonr(int* a, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);if (tmp == NULL){perror("malloc fail");exit(-1);}int gap = 1;//每次归并的长度while (gap < n){int i = 0;for (i = 0; i < n; i += gap * 2){int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + gap + gap - 1;if (begin2 >= n || end1 >= n)//要归并的第二个区间不存在,直接退出{//memcpy(tmp + i, a + i, sizeof(int) * (n - i));//把不归并的数据提前拷贝进tmp数组,防止因为a数组没有全部进行归并,tmp数组中存在随机值,//进而导致后续把tmp数组数据拷贝进a数组时,拷贝随机数据进a数组break;}if (end2 >= n)//要归并的第二个区间,右边越界,重置右区间{end2 = n - 1;}//printf("[%d,%d][%d,%d]", begin1, end1, begin2, end2);//打印每次归并区间int index = begin1;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){tmp[index++] = a[begin1++];}else{tmp[index++] = a[begin2++];}}while (begin1 <= end1){tmp[index++] = a[begin1++];}while (begin2 <= end2){tmp[index++] = a[begin2++];}memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));//每次归并完成后,把tmp中数据拷贝进a数组,防止丢失数据}//memcpy(a, tmp, sizeof(int) * n);//一趟归并后再把tmp数组的数据拷贝进a数gap *= 2;}free(tmp);
}

特性总结:

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

计数排序:

基本思想:

遍历数组,统计数组中每个元素的出现频率,再按顺序放回原数组。

需要注意的是,由于待排序列不一定是从0开始的且不知道要创建多大的数组进行计数,因此在遍历数组统计频率时,要同时找出最大最小值,每次计数时,用该位置数值减去最小值即为该数对应的下标,用最大值减去最小值再加1就是要创建的计数数组的大小

代码如下:

// 计数排序
void CountSort(int* a, int n)
{int min = a[0];int max = 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*)malloc(sizeof(int) * range);if (count == NULL){perror("malloc fail");exit(-1);}memset(count, 0, sizeof(int) * range);//每个数减去min就是对应的下标for (int i = 0; i < n; i++){count[a[i] - min]++;}//重新写入原数组,下标+min就是原始值int i = 0;for (int j = 0; j < range; j++){while (count[j]--){a[i++] = j + min;}}free(count);
}

特性总结:

1. 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限。
2. 时间复杂度:O(MAX(N,范围))
3. 空间复杂度:O(范围)

4. 稳定性:稳定

总结

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

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

相关文章

基于小波变换的分形信号r指数求解算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 ................................................................... %通过功率谱密度曲线…

华测监测预警系统 2.2 存在任意文件读取漏洞

华测监测预警系统 2.2 存在任意文件读取漏洞 一、 华测监测预警系统 2.2 简介二、漏洞描述三、影响版本四、fofa查询语句五、漏洞复现1、手动复现2、自动复现 六、修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信…

芯科蓝牙BG27开发笔记10-BG27样板调试

样板使用了1.5V电源&#xff0c;boost升压到1.8V供MCU使用&#xff0c;因此IO通信的电平需要注意&#xff1a; 不能使用常用的5V、3.3V的jlink进行调试&#xff0c;类似的uart通信也一样。 BRD4001A底板的jlink如何使用&#xff1f; 参考开发板套件的说明文档《ug551-brd4194…

小迈物联网网关对接串口服务器[Modbus RTU]

很多工控现场&#xff0c;方案中会使用串口服务器采集Modbus RTU的设备&#xff0c;这种情况下一般会在PC机上装上串口服务器厂家的软件来进行数据采集。如果现场不需要PC机&#xff0c;而是通过网关将数据传输到软件平台&#xff0c;如何实现呢&#xff1f; 本文简要介绍小迈网…

【TB作品】基于MSP430G2553单片机的超声波测距与报警系统,原理图,PCB

功能&#xff1a; 1 超声波测距显示 2 按键设置报警上下限 3 蜂鸣器报警 原理图&#xff1a; PCB样式&#xff1a; 实物&#xff1a; 代码&#xff1a; https://github.com/xddun/blog_code_search

DC/DC开关电源学习笔记(十二)Boost升压电路仿真及工程应用案例

(十二)Boost升压电路仿真及工程应用案例 1.Boost电路仿真案例2.Boost电路工程应用实例1.Boost电路仿真案例 指标参数:输入电压5V,输出电压12V,输出电流1A,开关频率10kHz,电压纹波0.5%。 根据输入指标参数确定CCM模式下各个关键元器件测参数: 负载电阻Rl=12R 占空比D=6…

Zabbix“专家坐诊”第206期问答汇总

问题一 Q&#xff1a;老师&#xff0c;我想配置一下监控项和触发器&#xff0c;目前我想要三个&#xff0c;内存的使用情况百分比、磁盘的剩余多少G、CPU的使用情况百分比&#xff0c;用自带的模板修改&#xff0c;该怎么做&#xff1f; A&#xff1a;可以用100减去内置键值cp…

数据结构学习笔记——数据结构概论

目录 一、数据与数据元素二、数据类型和抽象数据类型三、数据结构的定义&#xff08;一&#xff09;逻辑结构&#xff08;二&#xff09;存储结构&#xff08;物理结构&#xff09;1、顺序存储结构2、链式存储结构3、索引存储结构4、散列存储结构 &#xff08;三&#xff09;数…

Allegro基本规则设置指导书之Spacing规则设置

进入规则设置界面 1.设置Line 到其他的之间规则: 2.设置Pins 到其他的之间规则: 3.设置Vias 到其他的之间规则:

【C++初阶(一)】学习前言 命名空间与IO流

本专栏内容为&#xff1a;C学习专栏&#xff0c;分为初阶和进阶两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握C。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;C &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&…

Linux查看本机IP地址

Linux查看本机IP地址 命令 ipconfig可能会遇到的问题 Command ‘ifconfig’ not found, but can be installed with: Command ifconfig not found, but can be installed with:sudo apt install net-tools解决办法 安装net-tools再执行ipconfig 安装网络工具 sudo apt i…

Qt开发学习笔记02

将窗口设为提示框 Qt::ToolTipQt 数据库连接池 #ifndef SQLITE_H #define SQLITE_H#include <QSqlDatabase> #include <QSqlError> #include <QSqlQuery> #include <QQueue> #include <QMutex> #include <QDebug> #include "../con…

Redis之缓存一致性

Redis之缓存一致性 1 缓存更新策略1.1 内存淘汰1.2 过期删除1.3 主动更新1.4 三种缓存更新策略的对比 2 更新缓存的两种方式3 缓存更新策略的实现方式3.1 先更新DB&#xff0c;后更新缓存3.2 先更新DB&#xff0c;后删除缓存3.3 先更新缓存&#xff0c;后更新DB3.4 先删除缓存&…

二叉树的最近公共祖先

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

如何通过三行配置解决在Kubernetes中的gRPC扩展问题

一切都始于我向我们的高级软件工程师提出的一个问题&#xff1a; “忘掉通信速度。你真的觉得在gRPC中开发通信比REST更好吗&#xff1f;” 我不想听到的答案立刻就来了&#xff1a;“绝对是的。” 在我提出这个问题之前&#xff0c;我一直在监控我们的服务在滚动更新和扩展Po…

【k8s】ingress-nginx通过header路由到不同后端

K8S中ingress-nginx通过header路由到不同后端 背景 公司使用ingress-nginx作为网关的项目&#xff0c;需要在相同域名、uri&#xff0c;根据header将请求转发到不同的后端中在稳定发布的情况下&#xff0c;ingress-nginx是没有语法直接支持根据header做转发的。但是这个可以利…

【ARM Coresight 系列文章19 -- Performance Monitoring Unit(性能监测单元)

文章目录 1.1 PMU 介绍1.2 PMU 寄存器1.2.1 PMU 管理寄存器1.2.2 PMU 外设识别寄存器1.2.3 PMU 组件识别寄存器1.3 性能监控事件1.3.1 Cortex-A9 特定事件1.1 PMU 介绍 许多体系结构都包含 PMU(Performance Monitoring Unit)硬件,用于跟踪、计数系统内部的一些底层硬件事件…

[代码随想录]二叉树篇

文章目录 1. 二叉树之层序遍历1.1 144-二叉树的前序遍历1.2 94-二叉树的中序遍历1.3 145-二叉树的后序遍历1.4 102-二叉树的层序遍历1.5 107-二叉树的层序遍历II1.6 199-二叉树的右视图1.7* 637-二叉树的层平均值1.8* 429-N叉树的层序遍历1.9 515-在每个树行中找最大值1.10* 11…

k8s修改集群IP--重置集群

原来IP地址 192.168.10.138 k8s-master 192.168.10.139 k8s-node1 192.168.10.140 k8s-node2 新IP地址 192.168.10.148 k8s-master 192.168.10.149 k8s-node1 192.168.10.150 k8s-node2 cp -Rf /etc/kubernetes/ /etc/kubernetes-bak pki 证书目录保留下来&#xff1a; rm -rf …

Ubuntu18.04下载安装基于使用QT的pcl1.13+vtk8.2,以及卸载

一、QVTKWidget、QVTKWidget2、QVTKOpenGLWidget、QVTKOpenGLNativeWidget 区别 1.Qt版本 Qt5.4以前版本&#xff1a;QVTKWidget2/QVTKWidget。 Qt5.4以后版本&#xff1a;QVTKOpenGLWidget/QVTKOpenGLWidget。 2.VTK版本(Qt版本为5.4之后) 在VTK8.2以前的版本&#xff1a;QVT…