【数据结构初阶】九、排序的讲解和实现(直接插入 \ 希尔 \ 直接选择 \ 堆 \ 冒泡 -- C语言)
=========================================================================
相关代码gitee自取:
C语言学习日记: 加油努力 (gitee.com)
=========================================================================
接上期:
【数据结构初阶】八、非线性表里的二叉树(二叉树的实现 -- C语言链式结构)-CSDN博客
=========================================================================
排序
排序的概念
所谓排序,就是使一串记录,
按照其中的某个或某些关键字的大小,递增或递减排列起来的操作
稳定性
假定在待排序的记录序列中,存在多个具有相同关键字的记录,
若经过排序,这些记录的相对次序保持不变,
即在原序列中 r [ i ] = r [ j ] , 且 r [ i ] 在 r [ j ] 之前,
而在排序后的序列中,r [ i ] 仍在 r [ j ] 之前,
则称这种排序算法是稳定的;否则称为不稳定的
内部排序
数据元素全部放在内存中的排序
外部排序
数据元素太多,不能同时放在内存中,
根据排序过程的要求不能在内外存之间移动数据的排序
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
常见排序算法的实现
(详细解释在图片的注释中,代码分文件放下一标题处)
一、插入排序
插入排序 -- 直接插入排序
直接插入排序是一种简单的插入排序法
该算法基本思想:
把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,
直到所有的记录插入完为止,得到一个新的有序序列
(想象我们玩扑克牌时,给扑克牌大小排序就用了插入排序的思想)
实现思路:
当插入第 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)
- 该算法稳定性:稳定
---------------------------------------------------------------------------------------------
InsertSort函数 -- 直接插入排序实现函数
- 使用for循环进行循环插入排序,
再设置 “前元素” 和 “后元素”
- for循环中:
使用while循环为“后元素”寻找合适位置,
找到后再将 “后元素” 插入,
之后再次进行for循环让下个“后元素”插入合适位置图示:
该函数执行逻辑图:
对应函数测试:
---------------------------------------------------------------------------------------------
插入排序 -- 希尔排序(缩小增量排序)
希尔排序又称缩小增量法。
该算法基本思想:
先选定一个整数gap值,把待排序文件中所有记录分成gap个组,
所有距离为gap的记录分在同一组内,并对每一组内的记录进行直接插入排序,
然后换个整数gap值再取gap组,重复上述分组和排序的工作,
当 gap=1 时,所有记录在同一组内时已经排好序了
希尔排序的特性总结:
- 希尔排序是对直接插入排序的优化
- 当 gap>1 时都是在进行预排序,目的是让数组更接近于有序,
当 gap==1 时,数组已经接近有序的了,这样再进行直接插入排序就会很快,
这样整体而言,可以达到优化的效果
- 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,
因此在一些书中给出的希尔排序的时间复杂度也不固定,
该函数大概的时间复杂度为:O(N^1.3)
- 该算法稳定性:不稳定
---------------------------------------------------------------------------------------------
ShellSort函数 -- 希尔排序实现函数
- 核心实现操作还是直接插入排序,
但是在对所有值进行直接插入排序前先进行多次预排序操作,
(预排序也是用直接插入排序完成)
让数组达到尽量有序的状态
- 定义gap值变量,使用while循环控制多次预排序
(当gap==1时,就相当于直接插入排序)
- while循环中内嵌for循环完成“当前gap组”的预排序
- 再内嵌for循环完成“当前gap组”其中一组的预排序
(通过直接插入排序的方式实现)
- 最后再内嵌while循环配合完成直接插入排序
图示:
该函数执行逻辑图:
对应函数测试:
二、选择排序
基本思想:
每一趟排序从待排序的数组元素中分别选择出最小和最大的一个元素,
再分别存放在数组的起始位置和尾部位置,
直到全部待排序的数组元素排序完成
选择排序 -- 直接选择排序
该算法基本思想:
在元素集合 array[i] -- array[n-1] 中选择获取当前最小值元素和当前最大值元素,
将当前最小值元素交换后放到当前数组的起始位置,
将当前最大值元素交换后放到当前数组的尾部位置,在剩余的 array[i+1] -- array[n-2] 集合中,重复上述操作,直到集合剩余1个元素
直接选择排序的特性总结:
- 直接选择排序比较好理解,但是效率不高,实际很少使用
- 该算法时间复杂度:O(N^2)
- 该算法空间复杂度:O(1)
- 该算法稳定性:不稳定
---------------------------------------------------------------------------------------------
SelectSort函数 -- 直接选择排序实现函数
- 定义 数组开始(初始)位置下标begin 和 数组尾部(结束)位置下标end 变量,
使用while循环控制多趟直接选择排序
- (在while循环中:完成一趟直接选择排序)
定义 存放当前最小值下标mini 和 存放当前最大值下标maxi 变量,
内嵌for循环,遍历一次当前数组找到当前最大值和当前最小值
- (while循环中for循环外:)
将找到的当前数组最小值放入数组起始(左边)位置,
当前数组最大值放入数组尾部(右边)位置,
完成两值的排序后,调整 begin 和 end 变量,缩小数组范围准备下趟直接选择排序图示:
该函数执行逻辑图:
对应函数测试:
---------------------------------------------------------------------------------------------
选择排序 -- 堆排序
堆是一种完全二叉树,
可以使用堆中的向下调整操作对普通数组进行排序(升序或降序)
堆排序往期博客中已有详细描述:
【数据结构初阶】七、非线性表里的二叉树(堆的实现 -- C语言顺序结构)-CSDN博客
(包含堆排序的 实现函数、图示、对应函数执行逻辑图、函数测试、原代码)
三、交换排序
基本思想:
所谓交换,就是根据序列中两个记录键值的比较结果来交换这两个记录在序列中的位置
交换排序的特点:
将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动
交换排序 -- 冒泡排序
该算法基本思想:
数组中的元素1和元素2进行比较,如果元素1大于元素2,则交换两者位置;
再比较此时的元素2和元素3,如果元素2大于元素3,则交换两者位置;
再比较此时的元素3和元素4……
一趟冒泡排序完成后,就能完成当前数组中最大值的排序(排在尾部),
再进行下一趟冒泡排序前要缩小数组排序范围(排除已经排序好的最大值),这样多趟冒泡排序完成后就能完成数组的排序
冒泡排序的特性总结:
- 冒泡排序是一种非常容易理解的排序
- 该算法时间复杂度:O(N^2)
- 该算法空间复杂度:O(1)
- 该算法稳定性:稳定
---------------------------------------------------------------------------------------------
BubbleSort函数 -- 冒泡排序实现函数
- 定义嵌套for循环完成冒泡排序,
外层for循环控制当前数组范围,数组范围慢慢减小,
减到变成1时排序完成(至少有两个数才能比较)
- 内层for循环循环一趟完成当前数组范围内的最值的排序
- 在当前冒泡排序过程中,
设置一个变量exchange记录当前一趟冒泡排序过程中是否有发生元素的交换,
一趟冒泡排序后,如果没有任何元素发生交换,
说明目前已经排好序了,那就直接终止之后的冒泡排序图示:
该函数执行逻辑图:
对应函数测试:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
对应代码:
Sort.h -- 排序头文件
#pragma once//包含之后所需头文件: #include <stdio.h>//打印数组函数: void PrintArray(int* a, int n);//直接插入排序函数: //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n) void InsertSort(int* a, int n);//希尔排序函数: //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n) void ShellSort(int* a, int n); //1、预排序:分组排,间隔为gap(间距间隔)分为一组 // 预排序意义: // 让大的数更快的到数组后面,小的数更快的到数组前面, // gap值越大“跳”得越快,但是越不接近有序 // gap值越小“跳”得越慢,但是越接近有序 // 当gap==1时,就相当于直接插入排序 //2、直接插入排序//冒泡排序函数: //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n) void BubbleSort(int* a, int n); //直接选择排序函数: //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n) void SelectSort(int* a, int n);
---------------------------------------------------------------------------------------------
Sort.c -- 排序函数实现文件
#define _CRT_SECURE_NO_WARNINGS 1//包含排序头文件: #include "Sort.h"//打印数组函数: void PrintArray(int* a, int n) {for (int i = 0; i < n; i++){printf("%d ", a[i]);}printf(""); }//直接插入排序函数(升序): //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n) void InsertSort(int* a, int n) {//使用for循环进行循环插入排序:/*要取“前后元素”,“后元素”要依次和“前面所有元素”进行比较,直到“后元素”找到合适位置并插入,而“后元素”下标最大为[n-1],所以“前元素”下标最大为[n-2]*/for (int i = 0; i < n - 1; i++)//循环到 i = n-2 -- “前元素”下标最大为[n-2]:{//遍历下标的起始位置从 0 开始,到 n-2 结束:int end = i; //“前元素”//保存end下标元素的后一个元素:int tmp = a[end + 1]; //“后元素”//使用while循环为“后元素”寻找合适位置://(“后元素”循环和其前面所有元素进行比较,直到找到合适位置)while (end >= 0)//“前面所有元素”:下标 >=0 时就还有 “前元素”,//那“后元素”就需要继续进行比较:{if (tmp < a[end])//“后元素” 小于 “前元素”:{//那就将“前元素(较大)”往后插入(覆盖):a[end + 1] = a[end];//a[end + 1],被覆盖的元素还保留在tmp中,//所以不用担心覆盖后找不到“后元素”}else//"后元素" 大于等于 "前元素":{//说明“后元素”的“前面较大元素”都已经往后覆盖完成了,//找到了"后元素"的恰当位置,//break退出循环将“后元素”tmp插入该位置break;}end--;//当前end--,下次循环判断“前前元素”需不需要再往前覆盖,//end减到-1退出while循环的话,说明“后元素”是数组中最小的元素,//导致其前面所有元素都需要往后覆盖挪出位置}//注意,合适的位置是[end + 1],//因为"后元素" 大于等于 "前元素"的话,//那“后元素”就理应排在“前元素”后面,即[end + 1],a[end + 1] = tmp;//如果是end减到-1退出的while循环,//那[end + 1]就等于0,即数组首元素位置,//让“后元素”排在数组首元素位置} } //时间复杂度: //O(N^2) -- 逆序(最坏情况) //O(N) -- 顺序有序 //冒泡排序和插入排序论时间复杂度它们是同一档次, //但在细节上,如局部有序,插入排序会更优//希尔排序函数: //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n)· void ShellSort(int* a, int n) {//定义分组间隔和分组个数:int gap = n;//只要当前预排序gap值还没到1,//while循环就继续循环进行预排序:while (gap > 1){//变化gap值进行多次预排序,//让数组越来越接近有序:gap = gap / 2;//当 gap > 1 时就是预排序//当 gap == 1 时就是插入排序//这个for循环控制 “当前gap组” 的排序://(一组“gap分”组排完再排另一组gap分组)for (int j = 0; j < gap; j++)/** 假设gap取3,* 就在数组中以3(gap)为间隔取数为一组(gap分组)* 总共取3(gap)组*/{//这个for循环控制gap组中其中一组的排序:for (int i = 0; i < n - gap; i += gap)/** 循环条件:n - gap *控制“前元素end”范围,保证“后元素tmp”通过end取值时不出界* 迭代条件:i += gap*i每次迭代时就+gap,实现以gap为间隔取数为一组(gap分组)*/{//保存当前分组的“前元素”(记录):int end = i;//保存当前分组的“后元素”(记录):int tmp = a[end + gap];//使用while循环为“后元素”寻找合适位置://(“后元素”循环和其前面所有元素进行比较,直到找到合适位置)//(和直接插入类似,只是值与值间隔不同)while (end >= 0)//“前面所有元素”:下标 >=0 时就还有 “前元素”,//那“后元素”就需要继续进行比较:{if (tmp < a[end])//“后元素” 小于 “前元素”:{//(gap分组中:)//那就将“前元素(较大)”往后插入(覆盖):a[end + gap] = a[end];//a[end + gap],被覆盖的元素还保留在tmp中,//所以不用担心覆盖后找不到“后元素”end -= gap;//(gap分组中:)//当前end-=gap,下次循环判断“前前元素”需不需要再往前覆盖,//end减到<0时,退出while循环的话,说明“后元素”是数组中最小的元素,//导致其前面所有元素都需要往后覆盖挪出位置}else//"后元素" 大于等于 "前元素":{//说明“后元素”的“前面较大元素”都已经往后覆盖完成了,//找到了"后元素"的恰当位置,//break退出循环将“后元素”tmp插入该位置break;}}//注意,合适的位置是[end + gap],//因为"后元素" 大于等于 "前元素"的话,//那“后元素”就理应排在“前元素”后面,即[end + gap],a[end + gap] = tmp;//如果是 end减到<0 退出的while循环,//那[end + gap]就找到当前gap组首元素位置,//让“后元素”排在当前gap组首元素位置}}} }//两值交换函数: void Swap(int* x, int* y) {//创建中间值进行值的交换:int tmp = *x;*x = *y;*y = tmp; }//冒泡排序函数: //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n) void BubbleSort(int* a, int n) {/** 定义嵌套for循环完成冒泡排序:* 内层for循环一趟完成当前数组范围内的最值的排序* 外层for循环则控制当前数组范围* 数组范围慢慢减小,减到变成1时排序完成* (至少有两个数才能比较)*///这个for循环控制内嵌for循环的数组范围:for (int j = 0; j < n; j++){int exchange = 0; //如果没发生交换该变量就为0//内嵌for循环进行循环比较交换:for (int i = 1; i < n-j; i++)/**n-j :通过判断条件控制数组范围*因为一趟下来就完成一个当前最值的排序,*下次再排序的数组范围就要排除这个已经排好序的最值,*通过外部for循环的j来控制数组范围:*/{if (a[i - 1] > a[i])//如果“前元素” 大于 “当前元素”://( i 从1开始){//进行交换:Swap(&a[i - 1], &a[i]);exchange = 1;//如果发生了变化该变量就为1}}/** 内嵌for循环整个执行完就是一趟,* 当遇到最大值后,因为最大所以会一直被交换* 直到被交换至数组尾部,* 这就完成了当前数组最大值的排序*/if (exchange == 0)//一趟冒泡排序后,如果没有发生交换:{//说明目前已经排好序了,//就没必要再进行之后的冒泡排序了:break;} } }//直接选择排序函数: //第一个参数:接收要排序的数组首元素地址(a) //第二个参数:接收该数组的长度(n) void SelectSort(int* a, int n) {/** 思路:* 排序一趟选出当前最小值下标和当前最大值下标,* 通过对应下标将最小值放“左边”,最大值放“右边”*///数组开始位置下标 -- 0int begin = 0;//数组尾部(结束)位置下标 -- n-1int end = n - 1;//使用while循环控制多趟直接选择排序:while (begin < end)/** 只要 begin 还小于 end,左右下标就还没重合* begin 和 end 之间就还有元素要被排序*/{//对当前数组范围进行一趟直接选择排序://存放当前最小值下标:int mini = begin; //默认为下标0//存放当前最大值下标:int maxi = begin; //默认为下标0//使用for循环遍历一次当前数组,//找到当前最大值和当前最小值:for (int i = begin+1; i <= end; i++)/** mini 和 maxi 默认下标都是0* 所以循环时下标从[begin+1]开始,等于[n-1]结束*/{//选出当前最大值下标:if (a[i] > a[maxi])//如果“i下标元素”大于“maxi下标元素”:{//将较大值下标i赋给maxi下标:maxi = i;}//选出当前最小值下标:if (a[i] < a[mini])//如果“i下标元素”小于“mini下标元素”:{//将较小值下标i赋给mini下标:mini = i;}} //(for循环中)//将找到的当前数组最小值放入数组起始(左边)位置:Swap(&a[begin], &a[mini]);/** 注:如果begin下标元素为最大值,* 那么maxi下标也会指向该元素,即begin == maxi,* 当begin元素和mini交换后(只是值交换),* begin 和 maxi下标还是重叠在原位置,指向交换后的mini元素* 此时如果再执行 Swap(&a[end], &a[maxi]);* 就反而会将最小值移到数组尾部去,* 所以要调整 begin==maxi 重叠的情况:*/if (maxi == begin)//排除maxi和begin下标重叠的情况:{//maxi==begin等于当前最大值下标,上面交换后,//当前最大值就在mini下标处,//那就把maxi最大值下标指向mini下标处即可:maxi = mini;}//将找到的当前数组最大值放入数组尾部(右边)位置:Swap(&a[end], &a[maxi]);/** 执行到这就选出了两个最值并放到了合适位置(一趟直接选择排序),* 调整 begin 和 end 下标(调整数组范围),数组范围往中间缩小,* 再开始新一趟直接选择排序:*/++begin;--end;} //(while循环中) } //时间复杂度:O(N^2)
---------------------------------------------------------------------------------------------
Test.c -- 排序测试文件
#define _CRT_SECURE_NO_WARNINGS 1//包含排序头文件: #include "Sort.h"//插入排序测试: void ISTest() {//创建要进行插入排序的数组:int a[] = { 3,4,2,1,5 };//调用插入排序函数进行排序:InsertSort(a, 5);//循环打印排序后的数组:printf("使用直接插入排序后的数组:> ");for (int i = 0; i < 5; i++){printf("%d ", a[i]);} }//希尔排序测试: void SSTest() {//创建要进行插入排序的数组:int a[] = { 9,1,2,5,7,4,8,6,3,5 };//调用希尔排序函数进行排序:ShellSort(a, sizeof(a) / sizeof(int));//使用自定义打印函数打印排序后数组:printf("使用希尔排序后的数组:> ");PrintArray(a, sizeof(a) / sizeof(int)); }//冒泡排序测试: void BSTest() {//创建要进行插入排序的数组:int a[] = { 9,1,2,5,7,4,8,6,3,5 };//调用冒泡排序函数进行排序:BubbleSort(a, sizeof(a) / sizeof(int));//使用自定义打印函数打印排序后数组:printf("使用冒泡排序后的数组:> ");PrintArray(a, sizeof(a) / sizeof(int)); }//直接选择排序测试: void SlSTest() {//创建要进行插入排序的数组:int a[] = { 9,1,2,5,7,4,8,6,3,5 };//调用直接选择排序函数进行排序:SelectSort(a, sizeof(a) / sizeof(int));//使用自定义打印函数打印排序后数组:printf("使用直接选择排序后的数组:> ");PrintArray(a, sizeof(a) / sizeof(int)); }int main() {//ISTest();//SSTest();//BSTest();SlSTest();return 0; }
相关文章:

【数据结构初阶】九、排序的讲解和实现(直接插入 \ 希尔 \ 直接选择 \ 堆 \ 冒泡 -- C语言)
相关代码gitee自取: C语言学习日记: 加油努力 (gitee.com) 接上期: 【数据结构初阶】八、非线性表里的二叉树(二叉树的实现 -- C语言链式结构)-CSDN博客 排序 排序的概念 所谓排序,就是使一串记录,按照…...

uview组件使用笔记
图标样式 修改图标的样式 通过color参数修改图标的颜色通过size参数修改图标的大小,单位为rpx 效果图 <u-icon name"photo" color"#2979ff" size"28"></u-icon>图片图标 1.3.0 这里说的图片图标,指的是小…...

Linux1024一篇通俗易懂的liunx命令操作总结(第十课)
Linux1024一篇通俗易懂的liunx命令操作总结(第十课) 一 liunx 介绍 Linux是一种免费开源的操作系统,它的设计基于Unix。它最早是由芬兰的一位大学生Linus Torvalds在1991年开始编写的,取名为Linux。Linux具有高度的灵活性和可定制性,可以在…...

nuxt使用i18n进行中英文切换
中文效果图: 英文效果图: 版本: 安装: npm install --save nuxtjs/i18n 新建en.js与zh.js两个文件进行切换显示 en.js内容 import globals from ./../js/global_valexport default {/******* 公共内容开始* *****/seeMore: &quo…...

机器人制作开源方案 | 行星探测车实现WiFi视频遥控功能
1. 功能描述 本文示例所实现的功能为:用手机APP,通过WiFi通信遥控R261样机行星探测车移动,以及打开、关闭行星探测车太阳翼。 2. 电子硬件 在这个示例中,我们采用了以下硬件,请大家参考: 主控板 Basra主控…...
Angular main 中的enableProdMode
enableProdMode一次深度解析 在Angular的开发过程中,我们经常会遇到一个名为enableProdMode的设置。这个设置位于Angular的主模块(main module)中,它的主要作用是启用生产模式。那么,什么是生产模式?为什么…...

驱动day2:LED灯实现三盏灯的亮灭
head.h #ifndef __HEAD_H__ #define __HEAD_H__ #define PHY_PE_MODER 0x50006000 #define PHY_PF_MODER 0x50007000 #define PHY_PE_ODR 0x50006014 #define PHY_PF_ODR 0x50007014 #define PHY_RCC 0x50000A28#endif 应用程序 #include <stdio.h> #include <sys/…...
Android 编译错误:module xxx1 missing dependencies:xxx2
编译错误log module xxx1 missing dependencies:xxx2 分析方向 1.缺少依赖库 添加依赖库 shared_libs: ["libhidlbase","libhidltransport","libhwbinder","liblog","libutils","libcutils",],2.缺…...
使用EasyExcel实现Excel导入导出
介绍 EasyExcel是一个基于Java的、快速、简洁、解决大文件内存溢出的Excel处理工具。 他能让你在不用考虑性能、内存的等因素的情况下,快速完成Excel的读、写等功能。 快速:快速的读取excel中的数据。 简洁:映射excel和实体类,让…...

京东手机销售数据:2023年9月京东手机行业TOP10品牌排行榜
鲸参谋监测的京东平台9月份手机市场销售数据已出炉! 9月份,手机市场销售整体呈现下滑。鲸参谋数据显示,今年9月,京东平台手机销量为300万,环比下降约20%,同比下降约18%;销售额为92亿,…...
常量字符串
一、常量字符串是什么? 常量字符串是一个常量,它的值是首字符的地址 比如 "abcdefg" 或 "123456789" 就是常量字符串 二、常量字符串与普通字符串的区别 1.常量字符串不可更改,而普通字符串可以更改 利用memcpy内存…...

【活体检测】“深度学习驱动的人脸反欺诈检测系统:性能提升与多模型支持“
微调小视科技开源静默活体检测模型加载方式,性能提升8倍 I. 引言 在当今数字化时代,人脸反欺诈检测在各种应用中发挥着重要作用,从人脸识别到金融欺诈检测。为了满足不断增长的需求,深度学习技术已成为关键工具,但性…...
Howler.js HTML5声音引擎
介绍 Howler.js是一个不错的HTML5声音引擎。功能强大,性能不错,用起来也很方便。 1. 官网 https://howlerjs.com/ GitHub https://github.com/goldfire/howler.js 2. 兼容性 Howler默认使用Web Audio,但在IE上可以自动转为HTML 5 Audio。这…...
centos 7.9每天定期发送最新备份文件到另外一台服务器
1.需求 在本地化部署的过程中,为了使系统相对来说高可用,一般情况下,我们都会做一个负载,但是客户又会考虑成本,所以只有可怜巴巴的两台服务器,要全部服务都做负载,这个就实现不了。所以只能把…...
一文全面了解:一个神奇的 react-antd-admin 动态菜单
在React v18中使用React Router v6和Ant Design (antd) v5来动态生成菜单和路由,同时使用MockJS来模拟接口请求菜单数据,可以按照以下步骤进行: 创建一个React应用: 使用Create React App或您喜欢的其他方式创建一个React应用。 安装必要的依赖: 在项目目录中运行以下命令…...

二叉树,堆排序及TopK问题
要讲二叉树的概念,就要先讲树的概念。 树是什么呢? 树其实是一种储存数据的结构,因为他的结构倒过来和生活中的树很相似所以才被称之为树。 这是一颗多叉树,从最顶端的节点可以找到下边的几个节点,下边的节点又可以找…...
iphone xr密码错误太多次 连接itunes
itunes下载的固件在电脑在电脑的“C:\Users\用户名\AppData\Roaming\Apple Computer\iTunes\iPhone Software Updates”文件夹之中。 如果你忘记了 iPhone 密码 - 官方 Apple 支持 (中国) 下载和使用 Windows 10 版 iTunes - 官方 Apple 支持 (中国) 查找手机 iClo…...
设置RabbitMQ超时时间
RabbitMQ默认的超时时间是30分钟,在消息消费超过30分钟后,rabbitMQ会发生错误,导致整个channel被销毁,无法继续消费 在RabbitMQ安装的终端执行 rabbitmqctl eval application:set_env(rabbit,consumer_timeout,180000000). 命令…...

QT计时器
widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTimerEvent> //计时器类 #include <QTime> //时间类 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widg…...

3-k8s-镜像仓库harbor搭建
文章目录 一、概念二、安装harbor三、使用harbor仓库 一、概念 官方概念:Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器。 我们平时拉去镜像都是从线上仓库拉去,但是企业内部的镜像一般都不会随意传到网上,而是保存在自己公…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...