常见排序(c与c++)


常用排序类型


冒泡排序、选择排序、桶排序、快速排序、归并排序


具体算法详解


1、选择排序
假设有一组数,共n个,存在数组a中,从第一个数a【0】开始,与后面的数依次比较,找到一个比它大(小)的数就交换,共进行n-1轮。
【例】
初始 【49 38 97 65】
第一趟后 38【49 97 65】
第二趟后 38 49【97 65】
第三趟后 38 49 65【97】
程序模板:

void selectsort(int r[])  /r数组中存储数据/
{
    for(int i=1;i<=n-1;i++)
    {
        k=i;
        for(int j=i+1;j<=n;j++)
        {
            if(r[j]<r[k]) k=j;
        }
        if(k!=i)
        {
                    temp=r[i];
            r[i]=r[k];
            r[k]=temp;
        }
    }
}

2、冒泡排序
假设有一组数,共n个,从第一个开始,通过相邻两个数的比较,将大(小)数放前面,就第一次排序后,最小(大)的数最在最后面,每轮都从第n个数开始,共进行n-1轮。
由于排序的过程中总是大(小)数往前,小(大)数往前,相当于气泡的上升,所以称为冒泡排序。
【例】
初始 【4 5 7 1】
第一轮 :
1 【5 4】7 1
2 5【7 4】1
3 5 7【4 1】
第二轮:
1 【7 5】4 1
2 7 【5 4】1
第三轮 :
1 【7 5】4 1
程序模板:

void bubblesort(int r[])  /r数组中存储数据/
{
    for(int i=1;i<=n-1;i++)
    {
        for(int j=1;j<=n-i;j++)
        {
            if(r[j]<r[j+1])
            {
                temp=r[i];
                r[i]=r[k];
                r[k]=temp;
            }
        }
    }
}

由于有时发现排序等到一定时候,数据会已经排好,则之后就会进行多余的比较,从而增加不必要的排序时长,因此对程序进行如下改变:

void bubblesort(int r[])  /r数组中存储数据/
{
    int i=1;
    do
    {
        bo=true;
        for(int j=1;j<=n-i;j++)
        {
            if(r[j]<r[j+1])
            {
                temp=r[i];
                r[i]=r[k];
                r[k]=temp;
                bo=false;
            }
            i++;
        }
    }while(!bo);
}

3、桶排序
假设有一组数,共n个,将这n个在一定范围的数,依次存在下标为n的桶(数组)中,每个桶(数组)中可存若干个。
特点:待排数据有一定的范围。占用的空间相较前两种大,但时间上有减少(只进行了一轮循环)。
作用:①可将所有数据按顺序输出 ②可去重
程序模板:

void bucketsort(int a[]int n,int l,int r)  /a数组中存储数据,n是数据范围,l、r是数据范围的左右界/
{
    int k;
    memset(b,0,sizeof(b)); /此语句在程序段中,则题头必包含#include<cstring>,作用为将数组中的各元素清零/   
    for(int i=1;i<=n;i++)
        {
            cin>>k;
            a[i]++;
        }
        for(int i=l;i<=r;i++)
        {
             while(a[i]>0)
            {
                cout<<i<<" ";
                a[i]--;
            }
            cout<<endl;
        }
}

4、插入排序
假设有一组数,共n个,假设前面的m-1(m>=2)个数是有序的,则将第m个数插入到合适的位置,使得插入后,数据仍有序。
【例】
初始 【36】25 48 12
第一轮【25 36】48 12
第二轮【25 36 49】12
第三轮【12 25 36 49】
程序模板:

void insertsort(int a[])  /a数组中存储数据/
{
    for(int i=l;i<=r;i++)
     {
         x=a[i];/x中存储a[i]的值并在后将其与前面的数比较/
         j=i-1;
         while(x<a[j])
         {
             a[j+1]=a[j];
             j--;
         }
         a[j+1]=x;
     }
}

5、快速排序
是对冒泡排序的改进,但若数据不好则效率可能与冒泡相同。假设有一组数,共n个,用变量将其分成两个部分,变量i、j分别指向1、n,将两个变量往中间挪,当在左侧和右侧分别找到比它小的比它大的数,则将两数交换,直到j<=i,则调用自身,在左右两侧分别施行这种排序。
特点:速度快、不稳定`

void quicksort(int a[],int l,int r)  /a数组中存储数据l、r是数据范围的左右界/
{
    int i,j,mid,temp;
    i=l;
    j=r;
    mid=a[(l+r)/2];
    do
    {
        while(a[i]<mid) i++;
        while(a[j]>mid) j--;
        if(i<=j)
            {
                temp=a[i];
                a[i]=a[j];
                a[j]=temp;
                i++;
                j--;
            }    
    }while(i<j);//此处i、j不可相等
    if(l<j) quicksort(l,j);
    if(i<r) quicksort(i,r);
}

6、归并排序
将两个及以上的有序数列,合并成一个有序数列。
二路归并:假设有一组数,共n个,将i指向第一组数的第一个,j指向第二组数的第一个,k指向新数组的第一个,比较第i与第j个数,若第i个数小(大),则将第i个数赋到新数组的第k个,同时i与k同时加1,反之,一直循环此过程,直至一个组取完,则将另一组剩余的元素赋到新数组下标k及其以后的数组中。(三路、四路及以上的归并,原理相同)
(二路归并)程序模板:

void mergesort(int a[],int l,int m,int r)  /a数组中存储数据,m是第一组数的结束为止,l、r是数据范围的左右界/
{
    int i=l,j=m+1,k=l,b[r-l+1];/b数组中是存放排好序的数据/
    while(i<=m&&j<=r)
    {
        if(a[i]<=a[j])
         {
             b[k]=a[i];
             i++;
             k++;
         }
         else 
         {
             b[k]=a[j];
             j++;
             k++;
         }      
    }
    while(i<=m)
    {
        b[k]=a[i];
        i++;
        k++;
    }
    while(j<=r)
    {
        b[k]=a[j];
        j++;
        k++;
    }
}
接下来,则以二路归并的思路,再结合递归的思想,将归并排序写出。
程序模板:
void mergesort(int a[],int l,int r)  /a数组中存储数据,m是第一组数的结束为止,l、r是数据范围的左右界/
{
    int i=l,k=l,b[r-l+1];
    if(l==r) return;
    m=(l+r)/2;
    mergesort(l,m);
    mergesort(m+1,r);
    int j=m+1;
    while(i<=m&&j<=r)
    {
        if(a[i]<=a[j])
         {
             b[k]=a[i];
             i++;
             k++;
         }
         else
         {
             b[k]=a[j];
             j++;
             k++;
         }      
    }
    while(i<=m)
    {
        b[k]=a[i];
        i++;
        k++;
    }
    while(j<=r)
    {
        b[k]=a[j];
        j++;
        k++;
    }
    for(i=l;i<=r;i++) a[i]=b[i];
}

各种排序算法的比较


1、稳定性:
稳定:插入排序、冒泡排序、二叉树排序、二路归并及其它线性排序
不稳定:选择排序、希尔排序、快速排序、堆排序
2、时间复杂性
O(n^2):插入排序、冒泡排序、选择排序
O(nlog2n):快速排序、堆排序、归并排序
O(n):桶排序
注:若从最好的情况考虑,直接插入排序、冒泡排序最快;平均情况下,快速排序最快;最坏的情况下,堆排序、归并排序最快。
3、辅助空间
O(n):桶排序、二路归并
快速排序最好O(log2n),最差 O(n)
其余均为O(1)
4、其他
插入排序、冒泡排序速度较慢,但若参与的排序的序列局部或整体有序时,则速度较快,反而此时快速排序较慢。
当n较小时,且对稳定性不作要求宜用选择排序,对稳定性有做要求时,则用插入排序或冒泡排序。
桶排序的数据有一定的范围范围,若无空间相关要求,则适合用此种排序。
当n较大时,且元素较随机,对稳定性无要求,宜用快速排序。
当n较大时,且元素可能出现本身有序,对稳定性无要求,宜用堆排序。
快速排序是目前公认的最好的排序方式,若待排数据随机分布,则其用时最短。堆排序所用辅助空间相较快速排序少,且不会出现快排可能出现的最坏情况。但两种排序均不稳定。

c++中自带的排序——sort

注意:
1、必带algorithm的头文件
2、基本形式sort(arr+m,arr+n);
若不是单纯的按从小到大对一组数进行排序则引用函数(此处的示例为comp函数)用ort(arr+m,arr+n,comp);
①若要从大到小排,则写一个类似此种的函数:

int comp(const int &a,const int &b)
{
    return a>b;
}

②但若要对多个特征进行排序,则定义如下:

int comp(const stu&a,const stu&b)
{
    if(a.score>b.score) return 1;
    if(a.score<b.score) return 0;
    if(a.name<b.name) return 1;
    return 0;
}

将其引用到以下程序:

#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
struct stu
{
    int score;
    string name;
} a[100];
int n;
int comp(const stu&a,const stu&b)
{
    if(a.score>b.score) return 1;
    if(a.score<b.score) return 0;
    if(a.name<b.name) return 1;
    return 0;
}
int main()
{
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i].name;
        cin>>a[i].score;
    }
    sort(a,a+n,comp);
    for(int i=0;i<n;i++) cout<<a[i].name<<' '<<a[i].score<<endl;
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值