排序算法(学习之路1)

虽然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]<<' ';
}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值