【数据结构初阶】九、排序的讲解和实现(直接插入 \ 希尔 \ 直接选择 \ 堆 \ 冒泡 -- 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服务器。 我们平时拉去镜像都是从线上仓库拉去,但是企业内部的镜像一般都不会随意传到网上,而是保存在自己公…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)
引言 在人工智能飞速发展的今天,大语言模型(Large Language Models, LLMs)已成为技术领域的焦点。从智能写作到代码生成,LLM 的应用场景不断扩展,深刻改变了我们的工作和生活方式。然而,理解这些模型的内部…...











