排序问题的总结

前面介绍了选择排序、冒泡排序、插入排序、归并排序、堆排序、快速排序和桶排序,下面对这些排序算法进行总结。

实现

#include <iostream>
#include <stdlib.h>

using namespace std;

class Sort{
public:
    //插入排序
    static void insertionSort(int arr[],int length){
        if(arr == NULL || length <= 1){
            return;
        }
        int i = 1,j = 0;
        for( ; i < length; i++){
            for(j = i; arr[j] < arr[j - 1] && j > 0; j--){
                swap(arr[j],arr[j - 1]);
            }
        }
    }

    //快速排序
    static void quickSort(int arr[],int L,int R){
        if( L >= R)
            return;
        int num = arr[rand() % (R - L + 1)];
        //cout << num << endl;
        int less = L - 1;
        int more = R + 1;
        int i = L;
        while( i < R){
            if(arr[i] > num){
                swap(arr[i],arr[--more]);
            }
            else if( arr[i] < num) {
                swap(arr[i++],arr[++less]);
            }
            else{
                i++;
            }
        }
        quickSort(arr,L, less);
        quickSort(arr,more,R);

    }
    static void quickSort(int arr[],int length){
        if(arr == NULL || length <= 1){
            return;
        }
        quickSort(arr,0,length - 1);
    }

    //归并排序
    static void merge(int arr[],int L,int mid,int R){
        //cout << "L:" << L << " mid:" << mid << " R:" << R<< endl;
        int * temp_arr = new int(R - L + 1);
        int i = L,j = mid + 1,k = 0;
        while(i <= mid && j <= R){
            temp_arr[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
        }
        while(i <= mid){
            temp_arr[k++] = arr[i++];
        }
        while(j <= R){
            temp_arr[k++] = arr[j++];
        }
        for(i = L,k = 0; i <= R; i++){
            arr[i] = temp_arr[k++];
        }
    }

    static void mergeSort(int arr[],int L,int R){
        if( L >= R){
            return;
        }
        int mid = L + ((R - L) >> 1);//
        //cout << "mid: " << mid << endl;
        mergeSort(arr,L,mid);
        //cout << "mid + 1: " << mid + 1 << endl;
        mergeSort(arr,mid + 1,R);
        merge(arr,L,mid,R);
    }

    static void mergeSort(int arr[],int length){
        if(arr == NULL || length <= 1){
            return;
        }
        mergeSort(arr,0,length - 1);
    }

    //堆排序
    static void heapInsert(int arr[],int index){
       // cout << ((index - 1) >> 1) << endl;
        while(arr[index] > (arr[(index - 1) / 2])){
            swap(arr[index],arr[(index-1)/ 2]);
            index = ((index - 1) / 2);
        }
    }

    static void heapify(int arr[],int index,int heapSize){
        int L = index * 2 + 1;
        while ( L < heapSize){
            int largest = L + 1 < heapSize && arr[L + 1] > arr[L] ? L + 1 : L;
            largest = arr[largest] > arr[index] ? largest :index;
            if(largest == index)
                break;
            swap(arr[largest],arr[index]);
            index = largest;
            L = index * 2 + 1;
        }
    }

    static void heapSort(int arr[],int length){
        if(arr == NULL || length <= 1){
            return;
        }
        int i = 0;
        for( ; i < length; i++){
            heapInsert(arr,i);

        }
        int heapSize = length;
        swap(arr[0],arr[--heapSize]);
        while(heapSize > 0) {
            heapify(arr,0,heapSize);
            swap(arr[0],arr[--heapSize]);
        }
    }

    //计数排序
    static void countSort(int arr[],int length){
        if(arr == NULL || length <= 1){
            return;
        }
        int max = INT_MIN;
        cout << max << endl;
        int i = 0;
        for( ; i < length; i++){
            max = arr[i] > max ? arr[i]: max;
        }
        //cout << "max: " << max << endl;
        int* temp_arr = new int(max + 1);
        for(i = 0; i <=max; i++)
            temp_arr[i] = 0;
        for(i = 0; i < length; i++){
            temp_arr[arr[i]]++;
        }
        int j = 0;
        for(i = 0; i <= max;i++){
            while((temp_arr[i]--) > 0)
            arr[j++] = i;
        }
    }

    //基数排序

    //得到数组arr中最大的数是几位数
    static int getMaxBits(int arr[],int length){
        int max = INT_MIN;
        int i = 0;
        for( ; i < length; i++){
            max = arr[i] > max ? arr[i]: max;
        }
        for( i = 0; max != 0; i++){
            max /= 10;
        }
        return i;

    }
    //得到数字num的d位数是多少(如13的个位数字(d = 1)是3)
    static int getDigit(int num,int d){
        int i = 0;
        int divisor = 1;
        for( ; i < d; i++){
            divisor *= 10;
        }
        return num % divisor;
    }

    static void radixSort(int arr[],int begin,int end,int digit){
        const int radix = 10;
        int i = 0,j = 0;
        int* bucket = new int(end - begin + 1);//准备与原数组数量相同的桶
        int d = 1;
        //最大数字的最高位为digit位,从个位遍历digit位
        for( ; d <= digit; d++){
            int count_arr[radix] = {0};
            //从这里一直到193行的作用:arr数组中每个数字在d位是多少,为0则count[0]++,为1则count[1]++
            //然后将前一个数累加到后一个数字上,即arr[1] = arr[1] + arr[0],arr[1] 表示在d位上0--1的数字有多少个
            for(i = begin; i <= end; i++){
                count_arr[getDigit(arr[i],d)]++;
            }
            for(i = 1; i < radix;i++){
                count_arr[i] += count_arr[i - 1];
            }
            for(i = end;i >= begin;i--){
                int j = getDigit(arr[i],d);
                bucket[count_arr[j] - 1] = arr[i];
                count_arr[j]--;
            }
            for(i = begin,j = 0; i <= end; i++,j++ ){
                arr[i] = bucket[j];
                //cout << arr[i] << " ";
            }

        }
       // cout << endl;

    }

    static void radixSort(int arr[],int length){
        if(arr == NULL || length <= 1){
            return;
        }
        radixSort(arr,0,length - 1, getMaxBits(arr,length));
    }

    //for test
    static void printfArray(int arr[],int length){
        int i = 0;
        for( ; i < length; i++)
            cout << arr[i] << " ";
      //  cout << endl;
    }

};

int main()
{
    int arr[5] = {1,3,4,2,5};
    int i = 0;
    //Sort::insertionSort(arr,5);
    //Sort::quickSort(arr,5);
    //Sort::mergeSort(arr,5);
    //Sort::heapSort(arr,5);
    //Sort::countSort(arr,5);
    Sort::radixSort(arr,5);
    Sort::printfArray(arr,5);
    return 0;
}

比较

几个算法的时间复杂度、空间复杂度与稳定性如下:

排序算法时间复杂度空间复杂度稳定性
选择排序

O(N^2)

O(1)×
冒泡排序O(N^2)O(1)
插入排序O(N^2)O(1)
归并排序O(N*logN)

O(N)

堆排序O(N*logN)O(1)×
快速排序O(N*logN)O(logN)×

所谓稳定性,就是同样值的个体之间,如果不会因为排序操作而改变相对次序,那么这个排序方法就具有稳定性。

除了表中列出的排序算法,一切基于桶排序思想下的排序都是稳定的。

在数据量较小时,建议选择插入排序的算法,因为时间复杂度为O(N^2)的排序算法的额为的常数时间的操作较少,在数据量较小时反而比下面的时间复杂度更低的算法排序更快。另外,选择排序与冒泡排序的常数时间的操作都是固定的,而插入排序的操作数量与数据的质量有关,在最好的情况下,如果数组本身就是有序的,那么插入排序的时间复杂度为O(N)。

工程上对排序的改进

C++中,sort函数的声明如下:

#include <algorithm>
 
template< class RandomIt >
void sort( RandomIt first, RandomIt last );
 
template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp );

sort函数并不是简单的快速排序,除了对快速排序进行优化以外,它还会采用堆排序和插入排序。

当数据量比较大时采用快速排序,分段递归。一旦分段后的数据量小于某个阈值,为避免递归调用带来过大的额外负荷,便会改用插入排序。而如果递归层次过深,有出现最坏情况的倾向,还会改用堆排序。

优化后的快速排序:取整个数列的首、尾、中央三个地方的元素,以其中值作为分界值。分割的方法通常采用两个迭代器headtailhead从头端往尾端移动,tail从尾端往头端移动,当head遇到大于等于pivot的元素就停下来,tail遇到小于等于pivot的元素也停下来,若head迭代器仍然小于tail迭代器,即两者没有交叉,则互换元素,然后继续进行相同的动作,向中间逼近,直到两个迭代器交叉,结束一次分割。

实现:

template <class _RandomAccessIter>
inline void sort(_RandomAccessIter __first, _RandomAccessIter __last) {
  __STL_REQUIRES(_RandomAccessIter, _Mutable_RandomAccessIterator);
  __STL_REQUIRES(typename iterator_traits<_RandomAccessIter>::value_type,
                 _LessThanComparable);
  if (__first != __last) {
    __introsort_loop(__first, __last,
                     __VALUE_TYPE(__first),
                     __lg(__last - __first) * 2);
    __final_insertion_sort(__first, __last);
  }
}

 

详细可以参考:https://www.cnblogs.com/fengcc/p/5256337.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值