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

【数据结构】快速排序算法你会写几种?

在这里插入图片描述

👦个人主页:Weraphael
✍🏻作者简介:目前正在学习c++和算法
✈️专栏:数据结构
🐋 希望大家多多支持,咱一起进步!😁
如果文章有啥瑕疵
希望大佬指点一二
如果文章对你有帮助的话
欢迎 评论💬 点赞👍🏻 收藏 📂 加关注😍


目录

  • 一、hoare版本(左右指针法)
      • 1.1 算法思想
      • 1.2 hoare版本代码实现
      • 1.3 hoare版本性能分析
  • 二、 基准值选取随机值(优化)
  • 三、三数取中(优化)
  • 四、小区间优化
      • 4.1 思想
  • 五、三路划分(优化)
  • 六、快速排序之挖坑法
      • 6.1 算法思路
      • 6.2 代码实现
  • 七、前后指针法(最推荐的方法)
      • 7.1 算法思路
      • 7.2 代码实现
  • 八、非递归版快速排序
      • 8.1 前言
      • 8.2 实现方法
      • 8.3 代码实现

一、hoare版本(左右指针法)

1.1 算法思想

【思想】

  1. 任取待排序元素序列中的某元素作为 基准值key一般是第一个元素和最后一个元素。

  2. 【✨重点】 将待排序集合 分割成两子序列使得左子序列中所有元素均小于key,右子序列中所有元素均大于key

做法:定义两个变量ij分别指向开头和最后一个元素。请务必记住此结论:如果选取的基准值是第一个元素,要让j先动,反之让i先动。(假设选取的基准值为第一个元素并且要求序列为升序)

j遇到小于等于 key的数,则停下,然后i开始走,直到i遇到一个大于key的数时,将ij的内容交换,如果区间内还有元素,则重复以上操作。最后你会发现:ij最后一定会相遇(可以参考下面动图),此时将相遇点的内容与key交换即可

  1. 最后左右子序列重复该过程,直到所有元素都排列在相应位置上为止。(递归)

以下是一趟排序的动图演示

在这里插入图片描述

在往期博客中,我写了一篇快排算法模板,有兴趣的可以来看看:点击跳转

1.2 hoare版本代码实现

#include <stdio.h>void Swap(int* x, int* y)
{int t = *x;*x = *y;*y = t;
}// hoare版本
void quick_sort(int a[], int l, int r)
{// 如果区间只有一个元素或者没有元素,就没必要排序了if (l >= r) return;// 1. 选取一个基准值(以选取第一个元素为例)int key = a[l];// 2. 定义i和j,i从左向右走,j从右向左走。int i = l, j = r;while (i < j){// 注意:若选择第一个元素作为基准值,则需要j先走;反之让i先走while (i < j && a[j] >= key) // 找小{j--;}while (i < j && a[i] <= key) // 找大 {i++;}// 交换if (i < j)Swap(&a[i], &a[j]);}// 循环结束后,i和j一定会相遇,和基准值交换Swap(&a[l], &a[i]);// 3.递归quick_sort(a, l, i - 1);quick_sort(a, i + 1, r);
}  

【程序结果】

在这里插入图片描述

注意:这里会有一个越界 + 死循环问题 + 我犯的错误

在这里插入图片描述

  • while (i < j && a[j] >= key)循环中,如果不加i < j,那么假设序列已经是升序了,那么就会越界;while (i < j && a[i] <= key)也同理

在这里插入图片描述

  • 并且如果只写a[i] < key,将序列中出现数据冗余,就会陷入死循环
  • 最后还有一个问题,就是本人初学时犯的(忽略了一个小的知识点qwq)。

与基准值交换Swap(&a[l], &a[i]),不能写成Swap(&key, &a[i])。因为key是一个局部变量,只是存储序列a[l],虽然交换了,但是序列第一个元素并没有改变。我也是通过调试发现的hh

1.3 hoare版本性能分析

  • 时间复杂度

快速排序其实是二叉树结构的交换排序方法

在这里插入图片描述

递归的高度是logN,而单趟排序基本都要遍历一遍序列,大约有N个数,因此时间复杂度是NlogN

接下来可以和堆排序以及希尔排序来比较一下,它们三者的时间复杂度的量级都是NlogN

在这里插入图片描述

我们发现,当数据个数为一百万的时候,快速排序还是非常快的。不愧叫快排

那么快排最坏的情况是什么?

最坏的情况即包括逆序,也包括有序。其时间复杂度是O(N2)

在这里插入图片描述

如果数据量大的话,那么栈一定会爆。那如果是这样,快排还叫快排吗?

先说结论:快排的时间复杂度是:O(NlogN)

那么如何解决这个问题呢?通过分析发现,有序和无序就是因为基准值选取的不好。

因此,有人提出了优化基准值可以选取随机值或者三数取中

二、 基准值选取随机值(优化)

做法:使用rand函数随机选取区间中的下标rand() % (r - l),但是这样远远不够,因为递归的时候,左区间会随之改变。因此正确下标取法rand() % (r - l) + l

void quick_sort(int a[], int l, int r)
{if (l >= r) return;// 随机选key// 区间下标范围int randIdx = (rand() % (r - l)) + l; Swap(&a[l], &a[randIdx]);// 以下都和hoare版本一样int key = a[l];int i = l, j = r;while (i < j){while (i < j && a[j] >= key) {j--;}while (i < j && a[i] <= key){i++;}Swap(&a[i], &a[j]);}Swap(&a[l], &a[i]);quick_sort(a, l, i - 1);quick_sort(a, i + 1, r);
}

【程序结果】

在这里插入图片描述

三、三数取中(优化)

  • 三数取中是指:第一个元素、最后一个元素和中间元素,选出不是最小也不是最大的那一个(找的是下标)
int GetMinNum(int a[], int l, int r)
{int mid = (l + r) >> 1;// 选出不是最大也不是最小的// 两两比较if (a[l] < a[mid]){if (a[mid] < a[r]){return mid;}else if (a[r] < a[l]){return l;}else{return r;}}else // a[l] >= a[mid]{if (a[l] < a[r]){return l;}else if (a[r] < a[mid]){return mid;}else{return r;}}
}void quick_sort(int a[], int l, int r)
{if (l >= r)return;// 三数取中int mid = GetMinNum(a, l, r);Swap(&a[mid], &a[l]);// 以下和hoare版本一样int key = a[l];int i = l, j = r;while (i < j){while (i < j && a[j] >= key) {j--;}while (i < j && a[i] <= key){i++;}Swap(&a[i], &a[j]);}Swap(&a[l], &a[i]);quick_sort(a, l, i - 1);quick_sort(a, i + 1, r);
}

【程序结果】

在这里插入图片描述

四、小区间优化

4.1 思想

由于快速排序是基于分治的思想。其实就是二叉树结构的交换排序方法。而我们知道,二叉树最后一层的结点个数是占整个结点个数的一半。并且快排递归到最后每一个都是小区间,但是每一个小区间都需要使用多次递归。这样的消耗确实挺大。

因此我们可以对小区间进行优化,让小区间不要使用递归了,直接使用插入排序来进行优化。因为小区间以及很接近有序了。使用插入排序最佳。当然区间不可以太大,因为我们要考虑小区间直接插入的效率高于递归的效率

那区间的范围在多少合适呢?— 大概在10左右就行

#include <iostream>
using namespace std;void Swap(int *x, int *y)
{int t = *x;*x = *y;*y = t;
}int GetMinNum(int a[], int l, int r)
{int mid = (l + r) >> 1;// 选出不是最大也不是最小的// 两两比较if (a[l] < a[mid]){if (a[mid] < a[r]){return mid;}else if (a[r] < a[l]){return l;}else{return r;}}else // a[l] >= a[mid]{if (a[l] < a[r]){return l;}else if (a[r] < a[mid]){return mid;}else{return r;}}
}void InsertSort(int a[], int n)
{for (int i = 1; i < n; i++){int end = i - 1;int tmp = a[i];while (end >= 0){if (a[end] > tmp){a[end + 1] = a[end];end--;}else{break;}}a[end + 1] = tmp;}
}void QuickSort(int a[], int l, int r)
{if (l >= r)return;//  如果区间个数超过10,就使用递归if ((l - r + 1) > 10){// 三数取中int mid = GetMinNum(a, l, r);Swap(&a[mid], &a[l]);// 以下和hoare版本一样int key = a[l];int i = l, j = r;while (i < j){while (i < j && a[j] >= key){j--;}while (i < j && a[i] <= key){i++;}Swap(&a[i], &a[j]);}Swap(&a[l], &a[i]);QuickSort(a, l, i - 1);QuickSort(a, i + 1, r);}else{InsertSort(a + l, r - l + 1);}
}int main()
{int a[] = {9, 8, 7, 6, 5, 4, 3, 2, 1};int n = sizeof(a) / sizeof(a[0]);QuickSort(a, 0, n - 1);for (int i = 0; i < n; i++){printf("%d ", a[i]);}return 0;
}

五、三路划分(优化)

这个优化是为了解决大量元素重复的问题,这个博主还未学到。暂且先放放hh

六、快速排序之挖坑法

6.1 算法思路

在这里插入图片描述

【算法思路】

  1. 选取一个基准值并用一个变量保存(这个基值一般是第一个元素或者是最后一个元素),然后序列中基准值这个位置相当于是一个坑等待下一个元素填入
  2. 如果选取的基准值是第一个元素,老样子j要从右边向左开始找小,如果找到小,就将j指向的元素填入到坑中,而此时 j这个位置是一个坑等待填入;接下来就是i从左向右找大,如果找到了大,就将i指向的元素填入到坑中,同理的,i这个位置是一个坑等待填入
  3. 最后ij相遇,并且一起站着一个坑位hole,然后就把基准值key填入即可
  4. 递归重复区间[l, hole - 1]和区间[hole + 1, r]

本质上来说,填坑法和hoare版本类似,相比其更加容易理解

6.2 代码实现

void QuickSort5(int a[], int l, int r)
{if (l >= r) return;int x = a[l];// 如果选择左端点为基准值// 那么坑位一开始是以基准值为下标int hole = l;int i = l, j = r;while (i < j){while (i < j && a[j] >= x) // 找小{j--;}// 循环结束后,来到此处说明找到小了// 将小的填入上一个坑位// 再更新坑位a[hole] = a[j];hole = j;while (i < j && a[i] <= x){i++;}// 和上同理a[hole] = a[i];hole = i;}// 最后i和j相遇一定会同站一个坑位// 将基准值填入坑位即可a[hole] = x;// 递归QuickSort5(a, l, hole - 1);QuickSort5(a, hole + 1, r);
}

七、前后指针法(最推荐的方法)

7.1 算法思路

在这里插入图片描述

  1. 选出一个基准值key,一般是最左边或是最右边的。
  2. 起始时,prev指针指向序列开头,cur指针指向prev的下一个位置。
  3. cur指向的内容小于keyprev先向后移动一位,然后交换prevcur指针指向的内容,然后cur指针继续向后遍历
  4. cur指向的内容大于key,则cur指针直接向后遍历。因此可以得出结论,cur本质就是在找小,然后让小的往前靠
  5. cur超出序列,此时将keyprev指针指向的内容交换即可。

经过一次单趟排序,最终也能使得key左边的数据全部都小于keykey右边的数据全部都大于key

最后再重复以上操作,直至序列只有一个数据或者序列没有数据时。(递归区间[l, prev - 1][prev + 1, r]

7.2 代码实现

void quick_sort(int a[], int l, int r)
{if (l >= r)return;// 1. 选出一个keyint key = a[l];// 2. 起始时,prev指针指向序列开头,cur指针指向prev+1。int prev = l, cur = prev + 1;while (cur <= r){// 3. 若cur指向的内容小于key// 则prev先向后移动一位,// 然后交换prev和cur指针指向的内容,// 然后cur指针++(可以归到第四点)if (a[cur] < key){++prev;Swap(&a[prev], &a[cur]);}// 4. 若cur指向的内容大于key,则cur指针直接++++cur;}// 若cur到达r + 1位置,此时将key和prev指针指向的内容交换即可。Swap(&a[l], &a[prev]);// 递归quick_sort(a, l, prev - 1);quick_sort(a, prev + 1, r);
}

八、非递归版快速排序

8.1 前言

我们知道,递归会建立函数栈帧,递归层越深占用栈区的空间就会越大(栈的大小一般是8M或者10M)。当深度足够深时,栈区的空间就会被用完,导致栈溢出。所有最稳妥的方法就是使用非递归。

老实讲,快速排序一般不会发生栈溢出。因为大多数语言的快速排序算法的底层都是使用递归。

那么为啥还需要使用非递归来实现一遍呢?因为往后,如果递归发生栈溢出,就得使用非递归。因此,大家平常可以练习将递归改为非递归;另外,有些面试官为了考察代码能力,偶尔会叫我们手撕一个非递归版快速排序。

8.2 实现方法

快速排序的递归算法主要是在划分子区间,如果要非递归实现快速排序,只需要使用一个栈来维护一个区间即可。注意:要先入右区间,再如左区间。而栈又是先进后出的,因此满足递归是先展开左,再展开右

ps:一般将递归程序改为非递归,首先想到就是栈。因为递归本身就是一个压栈的过程。

更详细的步骤在代码注释里

8.3 代码实现

#include <iostream>
#include <stack>
using namespace std;int GetMinNum(int a[], int l, int r)
{int mid = (l + r) >> 1;// 选出不是最大也不是最小的// 两两比较if (a[l] < a[mid]){if (a[mid] < a[r]){return mid;}else if (a[r] < a[l]){return l;}else{return r;}}else // a[l] >= a[mid]{if (a[l] < a[r]){return l;}else if (a[r] < a[mid]){return mid;}else{return r;}}
}void Quick_sort(int a[], int l, int r)
{// 1. 用栈存储区间stack<int> st;// 2. 起始时,区间一定是存在的// 先入右,再如左st.push(r);st.push(l);// 如果栈不为空,说明还有区间需要排序while (!st.empty()){// 3. 取出区间 (栈顶一定是左区间)int begin = st.top();st.pop();int end = st.top();st.pop();// 4. 对取出的区间进行单趟排序// 以下内容就是三数取中的内容 int mid = GetMinNum(a, begin, end);swap(a[mid], a[begin]);int key = a[begin];int i = begin, j = end;while (i < j){while (i < j && a[j] >= key)j--;while (i < j && a[i] <= key)i++;if (i < j)swap(a[i], a[j]);}swap(a[begin], a[i]);// 5. 更新栈(更新区间) // [begin,i - 1] [i] [i + 1, end]// 先让右区间[i + 1, end]入栈 // 如果区间内有数则入栈// 判断条件写不写等都一样,一个数没必要排序if (i + 1 < end)  {st.push(end);st.push(i + 1);}if (begin < i - 1){st.push(i - 1);st.push(begin);}}
}

【程序结果】

在这里插入图片描述

相关文章:

【数据结构】快速排序算法你会写几种?

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;数据结构 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有帮助…...

C#访问修饰符

C#中的访问修饰符用于控制类型成员&#xff08;如字段、属性、方法等&#xff09;的访问级别。以下是C#中常用的访问修饰符&#xff1a; public&#xff1a;公共访问级别&#xff0c;没有任何访问限制。在任何其他类或程序集中都可以访问标记为 public 的成员。 private&#…...

anaconda中安装pytorch和TensorFlow环境并在不同环境中安装kernel

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…...

记一次解决Pyqt6/Pyside6添加QTreeView或QTreeWidget导致窗口卡死(未响应)的新路历程,打死我都想不到是这个原因

文章目录 💢 问题 💢🏡 环境 🏡📄 代码💯 解决方案 💯⚓️ 相关链接 ⚓️💢 问题 💢 我在窗口中添加了一个 QTreeWidget控件 ,但是程序在运行期间,只要鼠标进入到 QTreeWidget控件 内进行操作,时间超过几秒中就会出现窗口 未响应卡死的 状态 🏡 环境 �…...

用照片预测人的年龄【图像回归】

在图像分类任务中&#xff0c;卷积神经网络 (CNN) 是非常强大的神经网络架构。 然而&#xff0c;鲜为人知的是&#xff0c;它们同样能够执行图像回归任务。 图像分类和图像回归任务之间的基本区别在于分类任务中的目标变量&#xff08;我们试图预测的东西&#xff09;不是连续…...

Fork项目新分支如何同步

这里以seata项目为示例&#xff1a; 一、添加Fork仓库的源仓库 git remote add seata gitgithub.com:seata/seata.git二、fetch git fetch seata...

Linux 常用压缩格式

Linux 常用压缩格式简介 Linux系统用户可以根据自己的需求选择合适的压缩工具来进行文件压缩和解压操作。Linux系统中常用的压缩软件都有相应的命令行工具&#xff0c;并且可以通过软件包管理器进行安装。主要有gzip、bzip2、zip、tar、7z。 gzip&#xff1a;gzip是一个广泛使…...

高效背单词——单词APP安利

大英赛&#xff0c;CET四六级&#xff0c;以及考研英语&#xff0c;都在不远的未来再度来临&#xff0c;年复一年的考试不曾停息&#xff0c;想要取得好成绩&#xff0c;需要我们的重视并赋予相应的努力。对于应试英语&#xff0c;词汇量是不可忽略的硬性要求。相比于传统默写&…...

力扣 字母异位词分组 哈表 集合

&#x1f468;‍&#x1f3eb; 力扣 字母异位词分组 ⭐ 思路 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符串分别进行排序之后得到的字符串一定是相同的&#xff0c;故可以将排序之后的字符串作为哈希表的键。 &#x1f351; AC code class Solut…...

⑩⑤【DB】详解MySQL存储过程:变量、游标、存储函数、循环,判断语句、参数传递..

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL存储过程 1. 介绍2. 使用3. 变量①系统变…...

使用SpringBoot进行游戏服务器开发

背景&#xff1a; 之前一直只考虑用JavaSe进行游戏服务器开发&#xff0c;目前项目使用了Spring&#xff0c;发现还是非常好的&#xff0c;好处如下: 好处1:依赖注入非常方便&#xff0c;我们只使用Spring最基本的功能即可&#xff0c;这样子就算是有一些模块不使用Spring管理…...

数据结构——树状数组

文章目录 前言问题引入问题分析树状数组lowbit树状数组特性初始化一个树状数组更新操作前缀和计算区间查询 总结 前言 原题的连接 最近刷leetcode的每日一题的时候&#xff0c;遇到了一个区间查询的问题&#xff0c;使用了一种特殊的数据结构树状数组&#xff0c;学习完之后我…...

Untiy 使用RotateAround()方法实现物体围绕某个点或者某个物体旋转

Untiy 实现物体围绕指定点或者某个物体旋转&#xff0c;可使用RotateAround()方法。 语法&#xff1a; public void RotateAround(Vector3 point, Vector3 axis, float angle); 其中&#xff0c;point:旋转中心点位置&#xff1b; axis:要围绕的轴&#xff0c;如x,y,z angel…...

图像分类(五) 全面解读复现ResNet

解读 Abstract—摘要 翻译 更深的神经网络往往更难以训练&#xff0c;我们在此提出一个残差学习的框架&#xff0c;以减轻网络的训练负担&#xff0c;这是个比以往的网络要深的多的网络。我们明确地将层作为输入学习残差函数&#xff0c;而不是学习未知的函数。我们提供了非…...

使用html2canvas转换table为图片时合并单元格rowspan失效,无边框显示问题解决(React实现)

最近使用 html2canvas导出Table表单为图片&#xff0c;但是转换出的图片被合并的单元格没有显示边框 查了原因是因为我为tr设置了背景色&#xff0c;然后td设置了rowspan&#xff0c;设置了rowspan的单元格就会出现边框不显示的问题。 解决方法就是取消tr的背景色&#xff0c;然…...

pandas教程:Time Series Basics 时间序列基础

文章目录 11.2 Time Series Basics&#xff08;时间序列基础&#xff09;1 Indexing, Selection, Subsetting&#xff08;索引&#xff0c;选择&#xff0c;取子集&#xff09;2 Time Series with Duplicate Indices&#xff08;重复索引的时间序列&#xff09; 11.2 Time Seri…...

【C++初阶】STL详解(四)vector的模拟实现

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

Zookeeper学习笔记(2)—— Zookeeper API简单操作

前置知识&#xff1a;Zookeeper学习笔记&#xff08;1&#xff09;—— 基础知识-CSDN博客 Zookeeper集群搭建部分 前提&#xff1a;保证zookeeper集群处于启动状态 环境搭建 依赖配置 <dependencies><dependency><groupId>junit</groupId><arti…...

YOLOv8-Seg改进:Backbone改进 |Next-ViT堆栈NCB和NTB 构建先进的CNN-Transformer混合架构

🚀🚀🚀本文改进:Next-ViT堆栈NCB和NTB 构建先进的CNN-Transformer混合架构,包括nextvit_small, nextvit_base, nextvit_large,相比较yolov8-seg各个版本如下: layersparametersgradientsGFLOPsnextvit_small61033841075...

DocCMS keyword SQL注入漏洞复现 [附POC]

文章目录 DocCMS keyword SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现 0x06 修复建议 DocCMS keyword SQL注入漏洞复现 [附POC] 0x01 前言 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

如何在最短时间内提升打ctf(web)的水平?

刚刚刷完2遍 bugku 的 web 题&#xff0c;前来答题。 每个人对刷题理解是不同&#xff0c;有的人是看了writeup就等于刷了&#xff0c;有的人是收藏了writeup就等于刷了&#xff0c;有的人是跟着writeup做了一遍就等于刷了&#xff0c;还有的人是独立思考做了一遍就等于刷了。…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...