快速排序快排在c++中sort()函数应用

快速排序-sort()函数使用

  • c++中sort()排序函数使用
    • 1. 需要注意的是
    • 2.sort()函数使用
    • 3.sort() 函数的效率
    • 补充:快速排序
      • 1.算法步骤
      • 2.代码实现:
      • 3.效率(时间复杂度)

c++中sort()排序函数使用

1. 需要注意的是

sort() 函数受到底层实现方式的限制,它仅适用于普通数组和部分类型的容器。换句话说,只有普通数组和具备以下条件的容器,才能使用 sort() 函数:

1.容器支持的迭代器类型必须为随机访问迭代器。这意味着,sort() 只对 array、vector、deque 这 3 个容器提供支持。
2.如果对容器中指定区域的元素做默认升序排序,则元素类型必须支持<小于运算符;同样,如果选用标准库提供的其它排序规则,元素类型也必须支持该规则底层实现所用的比较运算符;
3.sort() 函数在实现排序时,需要交换容器中元素的存储位置。这种情况下,如果容器中存储的是自定义的类对象,则该类的内部必须提供移动构造函数和移动赋值运算符。
4.另外还需要注意的一点是,对于指定区域内值相等的元素,sort() 函数无法保证它们的相对位置不发生改变。
(如果有这方面需求可以用stable_sort (first, last)函数)



2.sort()函数使用

1、使用sort函数头文件需要#include< algorithm >或者直接用万能头文件,我一般直接用万能头文件

2、sort含三个参数:
sort (begin,end,cmp)
begin:要排序数组的起始地址(第一个数据的地址)
end:最后一个数据的下一个数据的地址

-cmp:不写,默认升序

快速排序快排在c++中sort()函数应用_第1张图片
cmp函数里写return a>b;实现降序
快速排序快排在c++中sort()函数应用_第2张图片

当然可以不用写cmp函数也可以完成降序功能

  • 升序:sort(begin,end,less());
  • 降序:sort(begin,end,greater());
  1. sort也可以利用迭代器完成字符的排序
  2. sort完成字符串的排序
  3. sort函数对结构体进行排序




    很多用法参考:c++ sort函数使用方法

3.sort() 函数的效率

该函数实现排序的平均时间复杂度为 N l o g 2 N N{log_2{N}} Nlog2N(其中 N 为指定区域 [first, last) 中 last 和 first 的距离)。

还有自定义排序规则使用(还挺好用)可以参考以下链接:
本节学习来源参考: c++sort()排序函数用法.

补充:快速排序

1.算法步骤

  1. 从数列中挑出一个元素,称为 “基准”(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

2.代码实现:

C++:

// 参考:http://www.dutor.net/index.php/2011/04/recursive-iterative-quick-sort/
struct Range {
    int start, end;
    Range(int s = 0, int e = 0) {
        start = s, end = e;
    }
};
template <typename T> // 整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能
void quick_sort(T arr[], const int len) {
    if (len <= 0)
        return; // 避免len等於負值時宣告堆疊陣列當機
    // r[]模擬堆疊,p為數量,r[p++]為push,r[--p]為pop且取得元素
    Range r[len];
    int p = 0;
    r[p++] = Range(0, len - 1);
    while (p) {
        Range range = r[--p];
        if (range.start >= range.end)
            continue;
        T mid = arr[range.end];
        int left = range.start, right = range.end - 1;
        while (left < right) {
            while (arr[left] < mid && left < right) left++;
            while (arr[right] >= mid && left < right) right--;
            std::swap(arr[left], arr[right]);
        }
        if (arr[left] >= arr[range.end])
            std::swap(arr[left], arr[range.end]);
        else
            left++;
        r[p++] = Range(range.start, left - 1);
        r[p++] = Range(left + 1, range.end);
    }
}

递归法:(To iterate is human. To recurse, divine.——L. Peter Deutsch)

template <typename T>
void quick_sort_recursive(T arr[], int start, int end) {
    if (start >= end)
        return;
    T mid = arr[end];
    int left = start, right = end - 1;
    while (left < right) { //在整个范围内搜寻比枢纽元值小或大的元素,然后将左侧元素与右侧元素交换
        while (arr[left] < mid && left < right) //试图在左侧找到一个比枢纽元更大的元素
            left++;
        while (arr[right] >= mid && left < right) //试图在右侧找到一个比枢纽元更小的元素
            right--;
        std::swap(arr[left], arr[right]); //交换元素
    }
    if (arr[left] >= arr[end])
        std::swap(arr[left], arr[end]);
    else
        left++;
    quick_sort_recursive(arr, start, left - 1);
    quick_sort_recursive(arr, left + 1, end);
}
template <typename T> //整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)、"大於"(>)、"不小於"(>=)的運算子功能
void quick_sort(T arr[], int len) {
    quick_sort_recursive(arr, 0, len - 1);
}

Java:

public class QuickSort implements IArraySort {

    @Override
    public int[] sort(int[] sourceArray) throws Exception {
        // 对 arr 进行拷贝,不改变参数内容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        return quickSort(arr, 0, arr.length - 1);
    }

    private int[] quickSort(int[] arr, int left, int right) {
        if (left < right) {
            int partitionIndex = partition(arr, left, right);
            quickSort(arr, left, partitionIndex - 1);
            quickSort(arr, partitionIndex + 1, right);
        }
        return arr;
    }

    private int partition(int[] arr, int left, int right) {
        // 设定基准值(pivot)
        int pivot = left;
        int index = pivot + 1;
        for (int i = index; i <= right; i++) {
            if (arr[i] < arr[pivot]) {
                swap(arr, i, index);
                index++;
            }
        }
        swap(arr, pivot, index - 1);
        return index - 1;
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

3.效率(时间复杂度)

快速排序最好时间复杂度为 O ( N l o g 2 N ) O(N{log_2{N}}) O(Nlog2N) ,最坏时间复杂度为 O(N2) ,平均时间复杂度为 O ( N l o g 2 N ) O(N{log_2{N}}) O(Nlog2N)

注意:快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。

参考:快速排序

递归算法的时间复杂度公式:T[n] = aT[n/b] + f(n) ;
最优情况下时间复杂度
快速排序最优的情况就是每一次取到的元素都刚好平分整个数组;
此时的时间复杂度公式则为:T[n] = 2T[n/2] + f(n);T[n/2]为平分后的子数组的时间复杂度,f[n] 为平分这个数组时所花的时间;
下面来推算下,在最优的情况下快速排序时间复杂度的计算(用迭代法):
T[n] = 2T[n/2] + n ----------------第一次递归
令:n = n/2 = 2 { 2 T[n/4] + (n/2) } + n ----------------第二次递归

                                        =  2^2 T[ n/ (2^2) ] + 2n

            令:n = n/(2^2)   =  2^2  {  2 T[n/ (2^3) ]  + n/(2^2)}  +  2n                         ----------------第三次递归  

                                        =  2^3 T[  n/ (2^3) ]  + 3n

            ......................................................................................                        

            令:n = n/(  2^(m-1) )    =  2^m T[1]  + mn                                                  ----------------第m次递归(m次后结束)

           当最后平分的不能再平分时,也就是说把公式一直往下跌倒,到最后得到T[1]时,说明这个公式已经迭代完了(T[1]是常量了)。

           得到:T[n/ (2^m) ]  =  T[1]    ===>>   n = 2^m   ====>> m = logn;

           T[n] = 2^m T[1] + mn ;其中m = logn;

           T[n] = 2^(logn) T[1] + nlogn  =  n T[1] + nlogn  =  n + nlogn  ;其中n为元素个数

           又因为当n >=  2时:nlogn  >=  n  (也就是logn > 1),所以取后面的 nlogn;

           综上所述:快速排序最优的情况下时间复杂度为:O( nlogn )

最差情况下时间复杂度
最差的情况就是每一次取到的元素就是数组中最小/最大的,这种情况其实就是冒泡排序了(每一次都排好一个元素的顺序)

 这种情况时间复杂度就好计算了,就是冒泡排序的时间复杂度:T[n] = n * (n-1) = n^2 + n;

 综上所述:快速排序最差的情况下时间复杂度为:O( n^2 )

平均时间复杂度
快速排序的平均时间复杂度也是:O(nlogn)

其实这个空间复杂度不太好计算,因为有的人使用的是非就地排序,那样就不好计算了(因为有的人用到了辅助数组,所以这就要计算到你的元素个数了);我就分析下就地快速排序的空间复杂度吧;
首先就地快速排序使用的空间是O(1)的,也就是个常数级;而真正消耗空间的就是递归调用了,因为每次递归就要保持一些数据;
最优的情况下空间复杂度为:O(logn) ;每一次都平分数组的情况
最差的情况下空间复杂度为:O( n ) ;退化为冒泡排序的情况

本节学习来源参考: 快速排序时间空间复杂度.

你可能感兴趣的:(#,ACM,c++,算法,数据结构)