八大排序超详解(动图+源码)

💓博主个人主页:不是笨小孩👀
⏩专栏分类:数据结构与算法👀 刷题专栏👀 C语言👀
🚚代码仓库:笨小孩的代码库👀
⏩社区:不是笨小孩👀
🌹欢迎大家三连关注,一起学习,一起进步!!💓

在这里插入图片描述

排序算法

  • 排序的概念
  • 插入排序
  • 希尔排序
  • 选择排序
  • 冒泡排序
  • 堆排序
  • 快速排序
  • 归并排序
  • 计数排序

排序的概念

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

常见的排序算法:

在这里插入图片描述
除了这些排序以外,该有一个很奇怪的排序,计数排序,我们待会将,我们接下来,就从第一个排序开始:

插入排序

插入排序的思想很简单就是把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。插入排序可以理解为就是我们打扑克牌摸排的过程,摸一张排,依次比较然后将它插入的合适的位置。

我们看图:
在这里插入图片描述
这个排序很简单,根据图我们就可以把第一个数据当成有序的数据,然后后面的数据依次插入,直到将数据插入完,这样就有序了。

代码如下:

void InsertSort(int* arr, int n)
{for (int i = 0; i < n-1; i++){//end表示有序数据的最后一数的下标int end = i;//tmp保存需要插入的值int tmp = arr[end+1]; while (end >= 0){//依次比较如果比需要插入的数大,就往后移,否则就跳出循环if (arr[end] > tmp){arr[end + 1] = arr[end];end--;}else{break;}}//跳出循环后将需要插入的数据放到end后面的位置arr[end + 1] = tmp;}
}

总结:

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

希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数gap,把待排序文件中所有记录分成gap个组,所有距离为gap的记录分在同一组内,并对每一组内的记录进行排序。然后,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

插入排序第一步我们需要预排序
预排序后插入排序就很快了,直接使用插入排序就可以了。但是当我们的gap=1是,希尔排序就相当于插入排序了。这里gap可以取很多值,但是要保证最后一次gap=1.

在这里插入图片描述

代码如下:

void ShellSort(int* arr, int n)
{int gap = n;//要进行多趟排序while (gap > 1){//+1是为了保证gap最后一次等于1gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){//每次分别排gap组数据,每组间隔gap个数据,一共gap组int end = i;int tmp = arr[i + gap];while (end >= 0){if (arr[end] > tmp){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = tmp;}}
}

总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就 会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的 希尔排序的时间复杂度都不固定:我们记住大约就等于O(N^1.3)
  4. 稳定性:不稳定

选择排序

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

在这里插入图片描述

我们这里实现的是依次找大的,然后放到最后面,和图不太一样,但是思想都一样。

代码如下:

void SelectSort(int* arr, int n)
{int end = n - 1;while (end>0){//每次初始化最大在0处,防止maxi到已经在排好序的位置int maxi = 0;for (int i = 0; i <= end; i++){if (arr[i] > arr[maxi]){maxi = i;}}//找到后和最后一个数据交换Swap(&arr[maxi], &arr[end]);end--;}
}

选择排序我们这里可以优化一下,就是每次选出最小的和最大的,然后最小的放到左边,最大的放到右边,然后接着找剩余数据的最大最小,直到结束。

代码如下:

void SelectSort(int* arr, int n)
{int begin = 0;int end = n - 1;while (begin < end){int maxi = begin;int mini = begin;//依次找大和找小for (int i = begin; i <= end; i++){if (arr[mini] > arr[i]){mini = i;}if (arr[maxi] < arr[i]){maxi = i;}}//找到后将大的数据放到后面Swap(&arr[maxi], &arr[end]);//防止最小的数据在最后面被换走了,及时修正if (mini == end){mini = maxi;}Swap(&arr[mini], &arr[begin]);begin++;end--;}
}

总结:

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

冒泡排序

冒泡排序大多数人应该都知道,它的基本思想就是依次比较,将大的数据冒到最后然后重复前面的过程,就可以完成排序。

在这里插入图片描述
代码如下:

void BubbleSort(int* arr, int n)
{for (int i = 0; i < n - 1; i++){int flag = 1;for (int j = 1; j < n - i; j++){if (arr[j] < arr[j - 1]){Swap(arr + j, arr + j - 1);flag = 0;}}if (flag == 1){break;}}
}

总结:

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

堆排序

堆排序前面已经讲过一次了,这里就不做过多的解释了,想要详细了解请戳。
这里是引用

总结:

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

快速排序

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

我们每次可以将数组划分为两部分,keyi是那个选出来的数的最终的下标,然后第一次排序后就是[left,keyi-1],keyi,[keyi+1,right],我们每一趟要保证的是keyi左边的数据逗比key小,右边的都比它大,然后左区间重复这个操作,右区间也重复这个操作,这就有点像二叉树的前序遍历,直到每个区间只剩下一个值,或者区间不存在时,我们结束递归。

快排的整体框架:

void QuickSort(int* arr, int left, int right)
{if (left >= right){return;}int keyi = partSort(arr,left,right);QuickSort(arr,left, keyi - 1);QuickSort(arr,keyi + 1, right);}

这里的partSort就是我们的单趟排序,我们讲三种方法:

  1. hoare版本
    在这里插入图片描述

我们需要两个指针,一个从左边开始走,一个从右边开始走,再定义一个key,和keyi,keyi保存key的小标,如果左边左key就右边先走,右边左key就左边先走,,然后左边找比key大的数,右边找比key小的数,找到后交换,然后接着走,直到相遇,然后把相遇的位置和key交换一下。

为什么左边做key右边先走呢?

因为这样可以保证相遇的位置一定是比key小等于的数,相遇无非就是两种情况,L遇到R,R遇到L,如果是L遇到R,我们让右边先走,R停下的位置一定是比key小的数,如果是R遇L,假设数组中的数都比key大,所以key遇到L是就是等于key,所以我们左边做key让右边先走,是可以保证相遇位置一定比key小的。

代码如下:

int partSort1(int* arr, int left, int right)
{int keyi = left;while (left < right){//右边找小while (left < right && arr[right] >= arr[keyi]){right--;}//左边找大while (left < right && arr[left] <= arr[keyi]){left++;}Swap(&arr[left], &arr[right]);}Swap(&arr[left], &arr[keyi]);return left;
}
  1. 挖坑法
    在这里插入图片描述

我们还是将左边做key,然后保存它的值,然后它就是一个坑,还是两个指针,由于左边有一个坑,所以右边就要找小的数来填这个坑,然后将右边的那个位置变成新的坑,然后左边找大,找到后接着填坑,更新坑的位置,L和R一定有一个是坑,所以,当他们相遇时,那个位置一定是坑,然后将key放进去即可。

代码如下:

int partSort2(int* arr, int left, int right)
{int hole = arr[left];int keyi = left;while (left < right){while (left < right && arr[right] >= hole){right--;}arr[keyi] = arr[right];keyi = right;while (left < right && arr[left] <= hole){left++;}arr[keyi] = arr[left];keyi = left;}arr[keyi] = hole;return keyi;
}
  1. 前后指针法
    在这里插入图片描述

定义两个指针一个prev一个cur,cur用来遍历数组,还是用左边的值来做key,然后将cur找到比key小的值就和++prev位置的数交换直到遍历结束,然后再把prev位置的值可key交换即可。

代码如下:

int partSort3(int* arr, int left, int right)
{int keyi = left;int cur = left + 1;int prev = left;while (cur <= right){if (arr[cur] < arr[keyi]&&++prev!=cur){Swap(&arr[prev], &arr[cur]);}cur++;}Swap(&arr[prev], &arr[keyi]);return prev;
}

快速排序的非递归版本

非递归的话,我们用队列和栈都是可以的,但是想要模仿递归的路径的话我们就要使用栈,我们先把数组的整个区间放到栈里面,然后在进行一趟排序后,我们把排出来的左区间和右区间入栈,由于先走左边,所以就要先把右边的区间压栈,然后依次进行,只要区间存在,我们就压,只要栈不为空,就代表一直有区间未处理。所以我们就一直重复操作,当然单趟排序的话,用上面的那种方法都可以。

代码如下:

void QuickSortNonR(int* arr, int left, int right)
{Stack st;StackInit(&st);StackPush(&st,right);StackPush(&st, left);while (!StackEmpty(&st)){int begin = StackTop(&st);StackPop(&st);int end = StackTop(&st);StackPop(&st);int keyi = partSort1(arr, begin, end);if (keyi + 1 < end){StackPush(&st, end);StackPush(&st, keyi + 1);}if (keyi - 1 > begin){StackPush(&st, keyi - 1);StackPush(&st, begin);}}
}

快速排序,还可以优化,他的效率和选的key的关系很大,所以我们有种方法叫做三数取中,左边的值、右边的值、中间的值,然都找到这三个数中间的数,把他换到左边,就可以了。

总结:

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

归并排序

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

归并排序需要将区间分为两部分,然后两部分都要有序才能归并,那左右区间又可以分割,以此类推,当区间只有一个数的时候就可以认为有序,这时我们可以走一个类似与二叉树后序遍历的思路,我们想归并左右区间,但是左右区间都无序,我们就递归左边让左边有序,在递归右边让右边有序,最后再左右归并,就可以排好了。

在这里插入图片描述

我们这里就需要一个数组来保存我们归并的值,我们取两段区间的值依次比较,拿小的尾插到tmp数组中,等归并完再拷回原数组,即可。

代码如下:

void _MergeSort(int* arr, int left, int right,int* tmp)
{if (left >= right){return;}//分割区间int mid = (left + right) / 2;_MergeSort(arr, left, mid, tmp);_MergeSort(arr, mid+1, right, tmp);int begin1 = left, end1 = mid;int begin2 = mid + 1, end2 = right;int k = left;while (begin1 <= end1 && begin2 <= end2){//选小的来尾插if (arr[begin1] <= arr[begin2]){tmp[k++] = arr[begin1++];}else{tmp[k++] = arr[begin2++];}}//不管哪个没有拷贝完,因为区间是有序地,直接尾插就可以while (begin1 <= end1){tmp[k++] = arr[begin1++];}while (begin2 <= end2){tmp[k++] = arr[begin2++];}//拷贝回原数组memcpy(arr + left, tmp + left, (right - left + 1) * sizeof(int));}
void MergeSort(int* arr, int left, int right)
{int* tmp = (int*)malloc(sizeof(int) * (right - left + 1));//不能在这个函数中递归,不然每次都要开辟数组_MergeSort(arr, left, right,  tmp);free(tmp);
}

归并排序的非递归版本

我们会发现归并排序用队列和栈都用不了,但是我们可以使用循环来解决它,首先我们需要一个gap来记录每组归并的数据有几个,然后控制区间,来进行归并。
但是在归并中,会存在很多的越界问题,比如end1越界了,或者begin1越界了,但是这两种情况我们都很好处理,等处理到这种错误时我们可以看成只剩下一组数据,就可以不用动,放在原数就好,等待下一轮归,直接break跳出就可以,还有一种情况是end2越界了,这时还有一部分数据需要归并,那我们就调整end2为n-1就可以了。

在这里插入图片描述

代码如下:

void MergeSortNonR(int* arr, int n)
{int* tmp = (int*)malloc(sizeof(int) * n);int gap = 1;//gap表示每组数据的长度while (gap < n){for (int i = 0; i < n; i += 2 * gap){//控制区间int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + 2 * gap - 1;int k = i;//越界即使调整或退出if (end1 >= n || begin2 >= n){break;}if (end2 >= n){end2 = n - 1;}while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] <= arr[begin2]){tmp[k++] = arr[begin1++];}else{tmp[k++] = arr[begin2++];}}while (begin1 <= end1){tmp[k++] = arr[begin1++];}while (begin2 <= end2){tmp[k++] = arr[begin2++];}//每次归并完拷贝会原数组memcpy(arr+i, tmp+i, sizeof(int)*(end2-i+1));}gap *= 2;}free(tmp);
}

总结:

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

计数排序

计数排序是非常奇怪的排序,它不需要比较任何数据,他开辟一个和最大值一样的数组,然后将该数组初始化为0,然后原遍历数组,将原数组的值对应到我们开辟数组的下标,出现一次我们就++该位置,然后统计每个位置出现的次数,然后在依次拷贝回原数组,就可以了。
但是如果数据很大很集中,我们就没必要开那么大,会很浪费,我们需要找到最大值和最小值,然后使用相对位置,就可以了,每个数对应到减去最小值的那个小下标,这样我们数组也不用开的很大。

代码如下:

void CountSort(int* arr, int n)
{int min = arr[0];int max = arr[0];//找最大值和最小值for (int i = 0; i < n; i++){if (max < arr[i]){max = arr[i];}if (min > arr[i]){min = arr[i];}}//计算区间方便开数组int c =max-min+1;int* nums = (int*)malloc(sizeof(int) * c);memset(nums, 0, c * sizeof(int));//统计for (int i = 0; i < n; i++){nums[arr[i]-min]++;}int k = 0;//拷贝回原数组for (int i = 0; i < c; i++){while (nums[i]--){arr[k++] = i+min;}}free(nums);
}

总结:

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

各大排序的比较:
在这里插入图片描述
今天的分享就到这里感谢大家的关注和支持!

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

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

相关文章

虚幻5中Lumen提供哪些功能以及如何工作的

虚幻引擎 5 中的 Lumen 是一个完全动态的全局照明和反射系统。它可以在虚幻引擎 5 中使用&#xff0c;因此创作者无需自行设置。它是为下一代控制台和建筑可视化等高端可视化而设计的。那么它提供了哪些功能以及如何工作&#xff1f; 全局照明 当光离开光源时&#xff0c;它会…

负载均衡搭建

LVS-DR部署 [客户端] node1 192.168.157.148 [lvs] node2 192.168.157.142 [web服务器] node3 192.168.157.145 node4 192.168.157.146&#xff08;1&#xff09;[lvs] yum install -y ipvsadm.x86_64 配置LVS负载均衡服务 &#xff08;1&#xff09;手动添加LVS转发1&#xff…

系统架构设计专业技能 · 软件工程之软件测试与维护(六)【系统架构设计师】

系列文章目录 系统架构设计专业技能 网络规划与设计&#xff08;三&#xff09;【系统架构设计师】 系统架构设计专业技能 系统安全分析与设计&#xff08;四&#xff09;【系统架构设计师】 系统架构设计高级技能 软件架构设计&#xff08;一&#xff09;【系统架构设计师…

MAVEN利器:一文带你了解MAVEN以及如何配置

前言&#xff1a; 强大的构建工具——Maven。作为Java生态系统中的重要组成部分&#xff0c;Maven为开发人员提供了一种简单而高效的方式来构建、管理和发布Java项目。无论是小型项目还是大型企业级应用&#xff0c;Maven都能帮助开发人员轻松处理依赖管理、编译、测试和部署等…

YOLOV7改进:加入RCS-OSA模块,提升检测速度

1.该文章属于YOLOV5/YOLOV7/YOLOV8改进专栏,包含大量的改进方式,主要以2023年的最新文章和2022年的文章提出改进方式。 2.提供更加详细的改进方法,如将注意力机制添加到网络的不同位置,便于做实验,也可以当做论文的创新点。 2.涨点效果:RCS-OSA模块更加轻量化,有效提升检…

Spring Boot业务代码中使用@Transactional事务失效踩坑点总结

1.概述 接着之前我们对Spring AOP以及基于AOP实现事务控制的上文&#xff0c;今天我们来看看平时在项目业务开发中使用声明式事务Transactional的失效场景&#xff0c;并分析其失效原因&#xff0c;从而帮助开发人员尽量避免踩坑。 我们知道 Spring 声明式事务功能提供了极其…

Kafka 01——Kafka的安装及简单入门使用

Kafka 01——Kafka的安装及简单入门使用 1. 下载安装1.1 JDK的安装1.2 Zookeeper的安装1.2.1 关于Zookeeper版本的选择1.2.2 下载、安装Zookeeper 1.3 kafka的安装1.3.1 下载1.3.2 解压1.3.3 修改配置文件 2. 启动 kafka2.1 Kafka启动2.2 启动 kafka 遇到的问题2.2.1 问题12.2.…

Python爱心光波

文章目录 前言Turtle入门简单案例入门函数 爱心光波程序设计程序分析 尾声 前言 七夕要来啦&#xff0c;博主在闲暇之余创作了一个爱心光波&#xff0c;感兴趣的小伙伴们快来看看吧&#xff01; Turtle入门 Turtle 是一个简单而直观的绘图工具&#xff0c;它可以帮助你通过简…

面试笔记:Android 架构岗,一次4小时4面的体验

作者&#xff1a;橘子树 此次面试一共4面4小时&#xff0c;中间只有几分钟间隔。对持续的面试状态考验还是蛮大的。 关于面试的心态&#xff0c;保持悲观的乐观主义心态比较好。面前做面试准备时保持悲观&#xff0c;尽可能的做足准备。面后积极做复盘&#xff0c;乐观的接受最…

基于MIV的神经网络变量筛选

1.案例背景 一般神经网络中所包含的网络输人数据是研究者根据专业知识和经验预先选择好的,然而在许多实际应用中,由于没有清晰的理论依据,神经网络所包含的自变量即网络输入特征难以预先确定,如果将一些不重要的自变量也引入神经网络,会降低模型的精度,因此选择有意义的自变量特…

ECS服务器安装docker

​ 为了安装并配置 Docker &#xff0c;你的系统必须满足下列最低要求&#xff1a; 64 位 Linux 或 Windows 系统 如果使用 Linux &#xff0c;内核版本必须不低于 3.10 能够使用 sudo 权限的用户 在你系统 BIOS 上启用了 VT&#xff08;虚拟化技术&#xff09;支持 on your s…

大数据课程I4——Kafka的零拷贝技术

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 掌握Kafka的零拷贝技术&#xff1b; ⚪ 了解常规的文件传输过程&#xff1b; 一、常规的网络传输原理 表面上一个很简单的网络文件输出的过程&#xff0c;在OS底层&…

一百五十七、Kettle——Kettle最新的官网下载地址(之前的Kettle官网已经无法下载,真坑)

一、目的 之前使用的是kettle8.2&#xff0c;不需要额外下载pentaho-hadoop-shims-hdp30-8.2.2018.11.00-342.jar&#xff0c;因为kettle8.2本身自带 但是kettle8.2在Linux上安装后建立共享资源库又有问题&#xff0c;没办法&#xff0c;只能换成kettle9.3 结果&#xff0c;k…

华为网络篇 RIPv2的基础配置-25

难度 1复杂度1 目录 一、实验原理 1.1 RIP的版本 1.2 RIP的路由更新方式 1.3 RIP的计时器 1.4 RIP的防环机制 二、实验拓扑 三、实验步骤 四、实验过程 总结 一、实验原理 RIP&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;&am…

微服务概述-7

Shiro 框架 Shiro 是一个用于 Java 应用程序的安全框架。它提供了身份验证、授权、加密和会话管理等功能&#xff0c;可以帮助开发人员构建安全可靠的应用程序。 Java 中针对权限管理常见的有 2 个著名的框架&#xff1a;spring security 和 shiro shiro 基本概念 credentia…

机器学习笔记 - 基于C++的​​深度学习 二、实现卷积运算

一、卷积 卷积是信号处理领域的老朋友。最初的定义如下 在机器学习术语中: I(…)通常称为输入 K(…)作为内核,并且 F(…)作为给定K的I(x)的特征图。 虑多维离散域,我们可以将积分转换为以下求和 对于二维数字图像,我们可以将其重写为: <

编程练习(1)

目录 一.选择题 第一题&#xff1a; 第二题&#xff1a; 第三题&#xff1a; 第四题&#xff1a; 第五题&#xff1a; ​编辑 二.编程题 第一题&#xff1a; 第二题&#xff1a; 1.暴力方法&#xff1a; 2.数组法&#xff1a; 一.选择题 第一题&#xff1a; 解析&…

【vue】简洁优雅的火花线、趋势线

来由 在github发现个好看易用的vue趋势线组件&#xff0c;特此记录。 效果 趋势图生成后效果如上&#xff0c;线条为渐变色&#xff0c;可设置是否平滑。具体线条走势&#xff0c;根据数据动态生成。 使用 安装 npm i vuetrend -S 引入 import Vue from "vue"…

MySQL性能分析之慢查询日志查看

一、背景 MySQL的慢查询日志是MySQL提供的一种日志记录,他用来记录在MySQL中响应的时间超过阈值的语句,具体指运行时间超过long_query_time(默认是10秒)值的SQL,会被记录到慢查询日志中。 慢查询日志一般用于性能分析时开启,收集慢SQL然后通过explain进行全面分析,一…

时序预测 | MATLAB实现WOA-CNN-BiLSTM鲸鱼算法优化卷积双向长短期记忆神经网络时间序列预测

时序预测 | MATLAB实现WOA-CNN-BiLSTM鲸鱼算法优化卷积双向长短期记忆神经网络时间序列预测 目录 时序预测 | MATLAB实现WOA-CNN-BiLSTM鲸鱼算法优化卷积双向长短期记忆神经网络时间序列预测预测效果基本介绍程序设计学习总结参考资料 预测效果 基本介绍 时序预测 | MATLAB实现…