虽然sort()可以代替百行代码,但是为了更深入了解各种算法的本质,写此文章。
一:冒泡排序
1. 算法步骤(时间复杂度O(n²))
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
2.算法分析
根据此算法步骤分析,不难发现冒泡排序较为繁琐,运行时间与所给数据有很大关系:
如:若数据是正序,则无需交换;但数据是倒序,则得来n次循环。
3.举例:
3 2 1 4 5
根据算法步骤,每次都将相邻的大的与小的互相交换位置,则排序后序列为:
2 3 1 4 5
2 1 3 4 5
1 2 3 4 5
4.代码实现
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
int t=n; //便于减少每次已经排好数据的重复排序
for(int i=0;i<n;i++)
{
for(int j=0;j<t-1;j++)
{
if(a[j]>a[j+1])
{
swap(a[j],a[j+1]);
}
}
t--;
}
for(int i=0;i<n;i++) cout<<a[i]<<' ';
}
二:选择排序
1:算法步骤 (时间复杂度O(n²))
首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
重复第二步,直到所有元素均排序完毕。
2.算法分析
选择排序较为直观和易于理解,不需要占用额外空间,但时间复杂度依旧很高。
3.举例
3 2 1 5 4
根据算法步骤依次得到序列:
1 2 3 5 4
1 2 3 4 5
4.代码实现
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++)
{
int minn=i;
for(int j=i+1;j<n;j++)
if(a[j]<a[minn]) minn=j;
swap(a[i],a[minn]);
}
for(int i=0;i<n;i++) cout<<a[i]<<' ';
}
三:插入排序
1.算法步骤 (时间复杂度O(n²))
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
--摘自菜鸟教程
2.算法分析
该算法是更加易于理解的算法,但时间复杂度依旧很高。
3.举例
4 3 2 5 1
按照算法步骤每次操作后结果如下:
3 4 2 5 1
2 3 4 5 1
2 3 4 5 1
1 2 3 4 5
4.代码实现
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N];
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
for(int i=0;i<n;i++)
for(int j=i;j>0;j--)
if(a[j]<a[j-1]) swap(a[j],a[j-1]);
else break;
for(int i=0;i<n;i++) cout<<a[i]<<' ';
}
四:快速排序(平均时间复杂度O(nlogn))
1.算法步骤
(1)选取基准
(2)划分,根据选取的基准将数组划分成小于基准的部分和大于基准的部分
(3)递归求解小于基准和大于基准的部分
2.算法分析
快速排序不稳定,但平均下来效率较高,是最值得使用的排序算法之一。
3.代码
#include <iostream>
using namespace std;
const int N = 100010;
int q[N];
void quick_sort(int q[], int l, int r)
{
if (l >= r) return;
int i = l - 1, j = r + 1, x = q[l + r >> 1];
while (i < j)
{
do i ++ ; while (q[i] < x);
do j -- ; while (q[j] > x);
if (i < j) swap(q[i], q[j]);
}
quick_sort(q, l, j);
quick_sort(q, j + 1, r);
}
int main()
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]);
quick_sort(q, 0, n - 1);
for (int i = 0; i < n; i ++ ) printf("%d ", q[i]);
return 0;
}
五:归并排序(平均时间复杂度O(nlogn))
1.算法步骤(源自acwing)
2.代码
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],n,tem[N];
void merge(int a[],int l,int r)
{
if(l>=r) return;
int mid=l+r>>1;
merge(a,l,mid),merge(a,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid && j<=r)
if(a[i]<=a[j]) tem[k++]=a[i++];
else tem[k++]=a[j++];
while(i<=mid) tem[k++]=a[i++];
while(j<=r) tem[k++]=a[j++];
for(int i=l,j=0;i<=r;i++,j++) a[i]=tem[j];
}
int main()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
merge(a,0,n-1);
for(int i=0;i<n;i++) cout<<a[i]<<' ';
}