• 快速排序


    特点

    对于有n个数的数组来说,快速排序最坏情况下的时间复杂度是O(n^2)。但是,快速排序通常是在实际应用中最好的选择,因为它的平均性能非常好: 它的期望时间复杂度是 O(n lgn),而且,O(n lgn)中隐含的常数因子很小。它还是可以进行原址排序。STL algorithm中的sort函数就是使用快速排序。

    过程

    快速排序也是使用分治思想。其排序步骤为:

    分解:数组 A[p...r] 被划分为两个子数组 A[p...q-1] 和 A[q+1...r],使得 A[p...q-1]中的每个元素都小于等于A[q],A[q+1...r] 中的元素都大于 A[q]。

    解决:通过快速排序,对两个子数组也排序

    合并:因为是子数组是原址排序,所以不需要合并

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    int partition(int* arr, int p, int r)
    {
        int key = arr[r];
        int i = p - 1;
    
        for (int j = p; j < r; j++)
        {
            if (arr[j] < key)
            {
                i++;
                int tmp = arr[i];
                arr[i] = arr[j];
                arr[j] = tmp;
            }
        }
        int tmp = arr[i+1];
        arr[i+1] = arr[r];
        arr[r] = tmp;
    
        return i+1;
    }
    
    void quick_sort(int* arr, int p, int r)
    {
        if (p < r)
        {
            int q = partition(arr, p, r);
            quick_sort(arr, p, q-1);
            quick_sort(arr, q+1, r);
        }
    }
    
    int main()
    {
        int arr[] = {2,4,62,3,4,3,1,7,8,9,5};
        int len = sizeof(arr) / sizeof(int);
    
        quick_sort(arr, 0, len-1);
    
        for (int i = 0; i < len; ++i)
        {
            printf("%d ", arr[i]);
        }
        printf("
    ");
    
        return 0;
    }

     

    quick_sort函数入参表示:数组、开始下标、结束下标。下标都是闭区间。

    关键部分是partition函数,《算法导论》中的图:

    性能

    快速排序的运行时间依赖于划分是否平衡。如果划分平衡,时间复杂度O(n lgn),如果不平衡,时间复杂度 O(n^2)

    在最坏情况,就是划分产生的两个子问题分别包含 n-1 个元素和 0 个元素。如果每次递归都出现了这种不平衡,划分操作时间复杂度 O(n).

    T(n) = T(n-1) + O(n)

    所以时间复杂度为 1+2+3+...+n = O(n^2)

    最好情况下,partition得到的两个子问题的规模都不大于n/2.这时,算法运行时间关系是:

    T(n) = 2T(n-1) + O(n)

    时间复杂度为 O(n lgn),不过,复杂度的常数因子比堆排序、归并排序都要小

    稳定性

    快速排序是不稳定的。它可以保证 A[p...q] 的稳定性,但不能保证 A[q...r]的稳定性。

    比如数组:[2,7,7,1,1,5,6,4],快排之后,[2,1,1,4]保持顺序稳定,但是第一个7到了最后一位。

  • 相关阅读:
    Linux内存地址映射
    江湖行
    数组/指针/const/字符串常量的使用传值问题
    TI davinci DM6467通过串口0将UBL和u-boot写入NAND flash
    CCS5配置使用GenCodecPkg生成CODEC SERVER
    typedef用法和与define的区别
    VS2008项目移植到Linux
    bootargs中ip段各项解释
    Davinci-DM6467板子-外围器件的I2C地址的疑惑解答
    MFC中界面自适应
  • 原文地址:https://www.cnblogs.com/zuofaqi/p/9671965.html
Copyright © 2020-2023  润新知