什么是排序算法?

排序是日常生活中十分常见的现象,例如按照成绩高低进行排序、按照身高从矮到高排队等。

排序算法是一种用于将一组元素按照一定规则排列的算法。这种排序可以按照升序(从小到大)或降序(从大到小)的方式进行。排序算法是计算机科学中的基本问题之一,因为在实际应用中,经常需要对数据进行排序以便更方便地进行搜索、查找或其他操作。

img

相关概念

稳定性:相等的元素经过排序之后相对顺序是否发生了改变

img

  • 稳定:如果排序前a在b的前面,且a==b,排序之后a仍然在b前面,称该算法稳定
  • 不稳定:如果排序前a在b前面,且a==b,排序之后a可能在b后面,称该算法不稳定
  • 时间复杂度:排序数据时总的操作次数。反映当n变化时,操作次数呈现的变化规律。
  • 空间复杂度:指算法在计算机内执行时所需存储空间的度量。

img

基于比较的三大基础排序

冒泡排序

img

img

img

img

冒泡排序:依次比较两个相邻的元素,如果顺序错误就把他们交换过来。每次冒泡,最大(最小)的元素会经由交换“浮”到序列顶端。多次冒泡后,即可完成排序。

排序过程:

  1. 比较相邻的元素。如果第一个比第二个大,就交换它们两个
  2. 对每一对相邻元素做同样的工作,从开始第一个对到结尾的最后一对,这样的最后的元素就是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。(一趟下来,最大的那个数就排在了最后面,那么下一趟对前n-1个数做同样的操作,重复步骤1-3,直到排序完成)

时间复杂度:O(n2),稳定。

冒泡排序——基础版

#include <iostream>  
using namespace std; 
int a[101],n;
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for(int i = 1; i <= n-1; i++){
        for(int j = 1; j <= n - i; j++){
            if(a[j] > a[j + 1])
                swap(a[j], a[j + 1]);
        }
    }
    for(int i = 1; i <= n; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

冒泡排序优化——提前跳出:如果序列已经有序,就没有必要进行后面的循环。

#include <iostream>  
using namespace std; 
int a[101],n;
int main(){
    cin >> n;
    for(int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for(int i = 1; i <= n-1; i++){
        bool flag=true;
        for(int j = 1; j <= n - i; j++){
            if(a[j] > a[j + 1]){
                flag=false;
                swap(a[j], a[j + 1]);
            }    
        }
        if(flag) break;
    }
    for(int i = 1; i <= n; i++) {
        cout << a[i] << " ";
    }
    return 0;
}

选择排序

img

选择排序:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在待排序的数列的最前面。

排序过程:

  1. 在未排序的数列中找到最小元素,存放到已排序数列的结束位置的下一个位置。
  2. 从剩余未排序元素中继续寻找最小元素,然后放到已排序序列的末尾。
  3. 重复1-2步骤

时间复杂度:O(n2), 不稳定。

#include <iostream>
using namespace std;
int a[1001],n;
int main() {
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=n-1;i++){
        int mini=i;//打擂台,记录擂主 
        for(int j=i+1;j<=n;j++) {
            if(a[j]<a[mini]) {
                mini=j; 
            }
        }
        if(i!=mini)
            swap(a[i],a[mini]);
    }
    for(int i=1;i<=n;i++) {
        cout<<a[i]<< " ";
    }
    return 0;
}

插入排序

img

img

img

img

插入排序:通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。

排序过程:

  1. 从第一个元素开始,该元素认为已经被排序
  2. 取出下一个元素值,在已经排序的元素序列中从后向前扫描
  3. 如果在已排序序列扫描到的元素值大于新元素值,将扫描到的元素移到下一位置
  4. 重复步骤3,直到找到已排序的元素小于新元素的位置
  5. 将新元素插入到该位置后一个位置,完成一个元素的排序
  6. 从接下来的n-1个开始,重复步骤2-5,直到完成全部数据排序。

时间复杂度:O(n2), 稳定。

方法1:

#include <bits/stdc++.h>
using namespace std;
int n,a[1001];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=2;i<=n;i++){
        int j=i-1,x=a[i];
        while(j>=1&&x<a[j]){
            a[j+1]=a[j];//有序的元素向后移动 
            j--;//继续往前看 
        }
        a[j+1]=x;
    } 
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }
    return 0;
}

方法2:

#include <bits/stdc++.h>
using namespace std;
int n,a[1001];
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=2;i<=n;i++){
        int j=i;
        while(j>=1&&a[j]<a[j-1]){
            swap(a[j],a[j-1]);//直接交换元素 
            j--;//继续往前看 
        }
    } 
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }
    return 0;
}

基于分类的三大排序

计数排序

计数排序:是一种特殊的桶排序。桶的个数是可能出现的数据种类数。

计数数组:数组下标是桶的编号,通常为数据值,数组的值表示数据个数。

适用条件:待排序数据为整数,数据范围有限。

设数据个数为n,数据范围为k。

时间复杂度:O(n+k),额外空间复杂度:O(k),稳定。

img

最终数组:

img

#include <bits/stdc++.h>
using namespace std;
int n,a[1001],num;
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>num;
        a[num]++;
    }
    for(int i=0;i<=1000;i++){
        for(int j=1;j<=a[i];j++){
            cout<<i<<" ";
        }
    }
    return 0;
}

桶排序

img

img

桶排序:将数据分到有限数量的有序的桶里,每个桶内分别排序,最后将各个桶中的数据合并。

数据分配到桶:散列过程

img

基数排序

基数排序(Radix Sort)是桶排序的扩展,也是一种非比较型整数排序算法。

原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。

小结

计数排序、桶排序、基数排序都是基于分类的思想,利用了桶的概念,只是分类的依据不一样

计数排序:每个桶只存储单一值

桶排序:每个桶存储一定范围的数值

基数排序:根据值的每位数字来分配

sort排序函数

为什么使用sort?

排序非常常见,每次都自己写很麻烦存在选择的困扰:究竟用哪个排序好呢?

sort:近似优化后的快排,同时结合了其它排序

sort(begin,end,[cmp])
//begin:开始的地址  end:结束的地址
//cmp:比较的方式,如果不写的话默认调用<

比较函数:传入两个数组中元素类型的参数,返回第一个参数排在前面的条件。

若不写比较函数cmp,默认为升序排序。

#include <bits/stdc++.h>
using namespace std;
int n,a[1001];
bool cmp(int &a,int &b){
    return a>b;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    sort(a+1,a+1+n,cmp);
    for(int i=1;i<=n;i++){
        cout<<a[i]<<" ";
    }
    return 0;
}

训练题单

作业

Copyright ©图灵之星 2024,转载需注明出处该文件修订时间: 2025-03-22 16:22:25

results matching ""

    No results matching ""