算法笔记之简单排序

前言

这里涉及到三种时间复杂度高的排序算法,分别是冒泡排序选择排序插入排序。系统学习算法,提高编程能力,不能只会用封装好的函数库,也要知道底层原理。因此,不可眼高手低。后面面对其他较难的思想时会学习到时间复杂度较低的排序算法,如快速排序等,因此这里不进行讲解。等入门算法学习结束,再对所有排序算法进行总结。

1. 冒泡排序

算法思想:

==两两交换,一趟交换下来就会把最大(或者最小)的移到最右边,一共移动n-1趟==

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;

//冒泡排序
int main(){
    int n,a[100];
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];

    //优化标记
    int flag;

    //核心代码
    for(int i=1;i<=n-1;i++){  //交换n-1趟
        flag=1;
        for(int j=0;j<=n-1-i;j++){
            //当前位置和下一位进行比较,第一次j最大到n-2(倒数第二位)

            //从小到大排序,将数值大的向右移
            if(a[j]>a[j+1]){
                int temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
                flag=0;
            }

        }
        if(flag)    break;  //一趟下来没有进行大小交换,说明已经排序好
    }

    //输出
    for(int i=0;i<n;i++){
        cout<<a[i]<<' ';
    }
    return 0;
}

复杂度分析

时间复杂度:最坏情况:O(N^2)
最好情况:O(N)
空间复杂度:O(1)

2. 插入排序

算法思想:

选中元素i,i前面的数据已经排列完成,取出i元素在前面进行对比插入

注意:插入趟数是n-1,因为默认第一个数是已经排列好的状态,选中元素i从第二个到第n个

。若是从小到大排序,对比后移结束条件是比第i元素大则后移,小于等于第i个则插入并结束对比循环

#include<bits/stdc++.h>

using namespace std;

//选择排序
int main(){
    int n,a[55];
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];

    for(int i=1;i<n;i++){
        int tmp=a[i],j;
        for(j=i-1;j>=0;j--){
            if(a[j]>tmp)
                a[j+1]=a[j];
            else{
                //一定要跳出循环
                break;
            }
        }
        //当遇到a[j]比tmp小时,跳出循环
        //此时将tmp放在a[j+1],不能在跳出循环之前插入
        //就会导致最小值无法放在a[0]
        a[j+1]=tmp;

    }

    for(int i=0;i<n;i++){
        if(i==0)    cout<<a[i];
        else        cout<<' '<<a[i];
    }
    return 0;
}

复杂度分析

时间复杂度:最坏情况下为O(N*N),此时待排序列为逆序,或者说接近逆序
最好情况下为O(N),此时待排序列为升序,或者说接近升序。
空间复杂度:O(1)

3. 选择排序

算法思想:

每次从待排序列中选择最小值,放在序列的起始位置,知道全部排列完成。当然我们可以一趟筛选除最大值和最小值,放在末尾和首位,提高效率

容易看出有两层循环,第一层记录未排列序列的首位(和末尾),第二层来遍历筛选最小值(和最大值)

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;

//插入排序
int main(){
    int n,a[100];
    cin>>n;
    for(int i=0;i<n;i++)
        cin>>a[i];

    //核心代码
    //未排序列,只剩最后一个相当于已排序列,即只用循环到倒数第二个
    for(int i=0;i<n-1;i++){
        int tmp=a[i],cnt=i;
        for(int j=i;j<n;j++){   //该循环是找到
            if(a[j]<tmp){
                tmp=a[j];
                cnt=j;
            }
        }
        swap(a[i],a[cnt]);
    }

    //输出
    for(int i=0;i<n;i++){
        cout<<a[i]<<' ';
    }
    return 0;
}

同时记录最大值和最小值代码

//核心代码
//未排序列,只剩最后一个相当于已排序列,即只用循环到倒数第二个
for(int p=0,len=n-1;p<len;p++,len--){
    //用临时变量存放未排序列的第一个和最后一个
    int Maxtmp=a[len],Maxcnt=len,Mintmp=a[p],Mincnt=p;
    //对未排序列进行遍历,找最大值和最小值
    for(int i=p;i<=len;i++){
        if(Maxtmp<a[i]){
            Maxtmp=a[i];
            Maxcnt=i;
        }
        if(Mintmp>a[i]){
            Mintmp=a[i];
            Mincnt=i;
        }
    }

    //注意交换时容易出现的bug,如果刚好最大值在第一个,最小值在最后一个,则只需要交换一次
    if(p==Maxcnt && len==Mincnt)
        swap(a[p],a[Mincnt]);
    else{
        swap(a[p],a[Mincnt]);
        swap(a[len],a[Maxcnt]);
    }

}

复杂度分析

时间复杂度:最坏情况:O(N^2)
      最好情况:O(N^2)
空间复杂度:O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值