四大排序算法——插入排序、归并排序、快速排序和堆排序比较(收藏copy直接用)

本文深入对比了插入排序、快速排序、归并排序和堆排序的优缺点,详细解析了它们的时间复杂度、空间需求、稳定性及适用场景。并提供了各算法的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里,九九给大家比较一下四大排序的区别和优缺点,并把代码黏在下面,大家有需要自取,喜欢可以收藏哦~

  • 收藏不点关注的都是小狗,小狗!
  • 点赞不点关注的都是小猪,小猪!

时间复杂度

对于插入排序来说,一般情况下时间复杂度是O(n^2),而其他的三个排序算法时间复杂度是O(nlogn)。
但是这只是平均情况下,还有特殊情况。
如果对于基本有序的一组数据经行处理,那么插入排序会进化到O(nlogn)级别,而对于快速排序来说,则可能退化到O(n^2)级别。(为此快速排序优化了以时间种子选随机数来决定第一个元素——基数是谁,但是总体来说,还是没有插入排序优秀。)
而如果对于拥有大量相同元素的一组数据处理,归并排序就可能更占优势。但是快速排序还有一种优化算法——三路排序,直接有效地提高了排序的效率。

开辟新空间

归并排序需要重新开辟一份和所排数据大小一样的空间来进行排序。
而堆排序和插入排序只需要赋值的时候那一个额外空间,空间大小为O(1)。
对于快速排序,因为是一个归并的过程,额外空间就是归并的最大层数——O(logn)级别。

原地排序

归并排序必须开辟额外空间,来完成归并,才能完成排序。
而其他的排序都可以直接通过数组间交换元素来完成排序。

稳定性

什么叫稳定性呢?
其实很好理解,只不过是对于相等的元素来说,排序前和排序后,他们的位置不发生改变。
举个栗子:
4a 2 1 5 4b 8 3
排序之后稳定:1 2 3 4a 4b 5 8
排序之后不稳定:1 2 3 4b 4a 5 8

而插入排序和归并排序,都是稳定的排序。
快速排序和堆排序,都是不稳定的排序。

这个道理其实很简单,但也没办法讲,大家可以自己一步一步走走过程,会发现的确是这样。

总结

对于这四个算法来说,每种都有优缺点,但是比较之下,快速排序的优化发展的更顺利、更远,所以在有多种选择的时候,我们一般首选快速排序。
而如果确定了排序的对象需要考虑稳定性的话,通常选择归并排序。当然了,也可以写一个比较符号的运算符重载,以此来保证快速排序的稳定性。
而对于一些专门卡空间(很少见)的情况,对于时间放得更开的话,可以考虑插入排序和堆排序。

下面将四中算法贴在这里,喜欢请自取。(下次我一定写注释!这不是个好习惯)


//插入排序


#include <iostream>
#include <algorithm>
using namespace std;
template<typename T>
void insertionSort(T arr[], int n){

    for( int i = 1 ; i < n ; i ++ ) {

        T e = arr[i];
        int j;
        for (j = i; j > 0 && arr[j-1] > e; j--)
            arr[j] = arr[j-1];
        arr[j] = e;
    }

    return;
}
template<typename T>
void insertionSort(T arr[], int l, int r){

    for( int i = l+1 ; i <= r ; i ++ ) {

        T e = arr[i];
        int j;
        for (j = i; j > l && arr[j-1] > e; j--)
            arr[j] = arr[j-1];
        arr[j] = e;
    }

    return;
}



//归并排序


#include <iostream>
#include <algorithm>
using namespace std;
template<typename  T>
void __merge(T arr[], int l, int mid, int r){

    T aux[r-l+1];
    for( int i = l ; i <= r; i ++ )
        aux[i-l] = arr[i];

    int i = l, j = mid+1;
    for( int k = l ; k <= r; k ++ ){

        if( i > mid )   { arr[k] = aux[j-l]; j ++;}
        else if( j > r ){ arr[k] = aux[i-l]; i ++;}
        else if( aux[i-l] < aux[j-l] ){ arr[k] = aux[i-l]; i ++;}
        else                          { arr[k] = aux[j-l]; j ++;}
    }
}

template<typename T>
void __mergeSort(T arr[], int l, int r){

    if( r - l <= 15 ){
        insertionSort(arr, l, r);
        return;
    }

    int mid = (l+r)/2;
    __mergeSort(arr, l, mid);
    __mergeSort(arr, mid+1, r);
    if( arr[mid] > arr[mid+1] )
        __merge(arr, l, mid, r);
}

template<typename T>
void mergeSort(T arr[], int n){

    __mergeSort( arr , 0 , n-1 );
}


//快速排序(三路排序)


#include <iostream>
#include <ctime>
#include <algorithm>
using namespace std;
template <typename T>
int _partition(T arr[], int l, int r){
    swap( arr[l] , arr[rand()%(r-l+1)+l] );
    T v = arr[l];
    int j = l;
    for( int i = l + 1 ; i <= r ; i ++ )
        if( arr[i] < v ){
            j ++;
            swap( arr[j] , arr[i] );
        }

    swap( arr[l] , arr[j]);

    return j;
}

template <typename T>
int _partition2(T arr[], int l, int r){

    swap( arr[l] , arr[rand()%(r-l+1)+l] );
    T v = arr[l];
    int i = l+1, j = r;
    while( true ){
        while( i <= r && arr[i] < v )
            i ++;

        while( j >= l+1 && arr[j] > v )
            j --;

        if( i > j )
            break;

        swap( arr[i] , arr[j] );
        i ++;
        j --;
    }

    swap( arr[l] , arr[j]);

    return j;
}

template <typename T>
void _quickSort(T arr[], int l, int r){

//    if( l >= r )
//        return;
    if( r - l <= 15 ){
        insertionSort(arr,l,r);
        return;
    }

    int p = _partition2(arr, l, r);
    _quickSort(arr, l, p-1 );
    _quickSort(arr, p+1, r);
}

template <typename T>
void quickSort(T arr[], int n){

    srand(time(NULL));
    _quickSort(arr, 0, n-1);
}



//堆排序

template<typename T>
void __shiftDown(T a[],int n,int mm){
    int m=mm;
    int count=n;
    while(m*2+1<count){
            int k=m*2+1;
            if(k+1<count&&a[k+1]>a[k]){
                k++;
            }
            if(a[k]<=a[m])break;
            swap(a[k],a[m]);
            m=k;
        }
}
template<typename T>
void heapSort(T arr[],int n){
    for(int i=(n-1)/2;i>=0;i--){
        __shiftDown(arr,n,i);
    }
    for(int i=n-1;i>0;i--){
        swap(arr[0],arr[i]);
        __shiftDown(arr,i,0);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值