系列文章目录
1.高精度的计算
2.排序(1)
目录
一、什么是排序
排序就是将一个无序的数列按照一定规则排列成一个有序数列,常见的排序规则有从小到大和从大到小两种(当然,部分题目的排序方式可能会很特殊,下面所讲的仅仅是最基础的从小到大的排序方式)。举个例子,数列0、32、53、12、34、2、1、90按常用规则排序后为:
排序规则 | 排序后数列 |
---|---|
从小到大 | 0、1、2、12、32、34、53、90 |
从大到小 | 90、53、34、32、12、2、1、0 |
二、用什么方法排序
目前常用的排序方法有插入排序、选择排序、冒泡排序等八大排序,这些排序时间复杂度各异(当然,我很懒不会全讲的)。下面,我将列举这八大排序的时间、空间复杂度:
最坏时间复杂度 | 平均时间复杂度 | 空间复杂度 | |
---|---|---|---|
插入排序 | O(n^2) | O(n^2) | O(1) |
选择排序 | O(n^2) | O(n^2) | O(1) |
冒泡排序 | O(n^2) | O(n^2) | O(1) |
希尔排序 | O(n^s),1<s<2 | O(n log n) | O(1) |
快速排序 | O(n^2) | O(n log n) | O(log n) |
堆排序 | O(n log n) | O(n log n) | O(1) |
归并排序 | O(n log n) | O(n log n) | O(n) |
系统函数 | O(n log n) | O(n log n) | 不详 |
三、怎样排序
接下来我会详细讲解一些排序算法,所有代码均为从小到大的排序代码。当然,如果你认为文字不太好理解,可以去数据结构和算法动态可视化查看排序的过程。
3.1 冒泡排序
排序特点:每一个数值都会像水底的泡泡一样不断上升,直到到达合适的位置。
排序原理:就近比较两个数的值,如果前数大于后数,则交换两数,使数列逐渐变得有序。
代码示例(从小到大排序):
for (int i=n;i>=1;i--)//由冒泡排序的特点得:每次枚举后,就会固定一个数的位置
for (int j=1;j+1<=i;j++)//相邻两个数的比较
if (a[j]>a[j+1])
swap(a[j],a[j+1]);//交换两数
输入样例:
5
3 2 5 4 1
输出效果截图:
算法评估:时间复杂度为O(n^2),非常大,对于后期的题目来说,简直没啥用(那还讲它干啥)。
3.2 插入排序
排序特点:每次交换两个的值,基本没啥用。
排序原理:从最前一个数向后枚举,与后面的数进行比较。
代码示例:
for (int i=n;i>=1;i--)
for (int j=1;j<i;j++)
if (a[j]>a[i])
swap(a[j],a[i]);
输入样例:
7
10 3 7 6 2 3 1
输出效果截图:
算法评估: 时间复杂度为O(n^2),非常大,跟冒泡排序简直没差别。
3.3 堆排序
这个时候肯定有人站出来说了:“堆是个啥?”但恕我直言,这玩意儿虽然名为堆排序,也用到了堆的思想,但它真的十分简单(如果你不信,我也没办法了)。
排序特点:一个字:快,但弊端很明显(排序的数字最大不能超过2,000,000)
首先,需要两个数组,一个用于存储需要排序的数列以及排序后的数列(我将它命名为a),另一个用于归类(名字:b);首先,循环跑一遍a,用数组b纪录每个数字的个数,最后循环跑一遍b,再存到a中。啊呸,不说了(我实在解释不清,评论区的大佬可以帮忙解释一下),上代码。
#include <bits/stdc++.h>
using namespace std;
int n,a[200],b[2000000];
int main()
{
cin>>n;
for (int i=1;i<=n;i++)
cin>>a[i];
for (int i=1;i<=n;i++)
b[a[i]]++;
for (int i=1,j=0;i<=1999999;i++)
for (int k=1;k<=b[i];k++)
a[++j]=i;
for (int i=1;i<=n;i++)
cout<<a[i]<<" ";
return 0;
}
3.4 系统函数
排序原理:运用快速排序的优化,使得其在快排的基础上更加稳定。
函数原型:
sort(排序首地址,排序尾地址,排序规则函数);
前两个参数是必要的,最后一个可有可无(我承认这里用词不当了),代码示例:
sort(a+1,a+1+n);
算法评估:时间复杂度低,适用性强。
3.5 待更新
总结
排序算法千千万,唯有sort万人迷。插入排序时间慢,希尔排序不稳定 。
快速排序虽然快,但是要求特别高。堆排归排固然好,理解起来可复杂。
再见!