• 洛谷 P1177 【模板】快速排序


    题目所在网址:https://www.luogu.com.cn/problem/P1177

    题面说是快排的板子题,可将纯纯快排的板子扔上去之后 T 的一塌糊涂...看来没这么简单。

    对于快排,我的理解,一趟快排所做的事(从结果上来看)就是:把标准值扔到它最终该待的地方并且使它左边的值都小于它,右边的值都大于它。把这个过程扔到递归中去做足够多的的次数,就能够使一串数字排好顺序。

    我们知道,快排的时间效率会随给定的数列特征不同而变化:

    • 假如,我们每次选定的标准值,它最终待的地方都是中间位置,这样我们的快排每次都能从中间位置分割进而递归,第一趟确定一个数的位置,第二趟确定两个数的位置,第三趟确定四个数的位置......这样的话,一共排序的趟数是 logn,每趟的时间是 O(n) ,就达到了快排的最好时间复杂度:O(nlogn)
    • 假如,这串数字本来就是有序的,我们每次选定的标准值,它最终待的地方都是最边上的位置,这就意味着我们做完一趟快排,把标准值放在该放的位置之后,第二趟快排要对剩下的 n - 1 个数做,第三趟快排要对剩下的 n - 2 个数做......这样的话,一共排序的趟数是 n ,它的时间复杂度是 n + n-1 + n-2 + ... + 2 + 1 = n(n + 1) / 2,显然,为 O(n2),这便是快排最不拿手的情况。

    如何让我们的快排小兄弟不再怕这种情况?有两种思路:

      1、数据虽然很不友好,但我们设法在选取标准值的时候尽量随机。

    参考如下代码:

    int key = arr[(rand() % (high - low + 1)) + low];

    对于本题,你甚至可以这么写:

    int key = arr[(low + high) / 2];

      2,让数据变得友好

    拿到数据之后,我们可以人为的将其打乱,这个过程花费 O(n),但由于 打乱数据 和 快排 是顺序的关系,不会影响到整体的时间效率。

    参考如下代码:

    void disrupt(int arr[], int n){//O(n)打乱数组,提升快排效率
        int temp, t_rand;
        for(int i = 0; i < n; i++){
            temp = arr[i];
            t_rand = rand() % n;
            arr[i] = arr[t_rand];
            arr[t_rand] = temp;
        }
    }

    这样的快排板子,便能够顺利的通过本题。

    附上完整AC代码:

    1. #include<iostream>  
    2. #include<fstream>  
    3. #include<algorithm>  
    4. #include<cstdlib>  
    5. #include<ctime>  
    6. using namespace std;  
    7.   
    8. void disrupt(int arr[], int n){//O(n)打乱数组,提升快排效率  
    9.     int temp, t_rand;  
    10.     for(int i = 0; i < n; i++){  
    11.         temp = arr[i];  
    12.         t_rand = rand() % n;  
    13.         arr[i] = arr[t_rand];  
    14.         arr[t_rand] = temp;  
    15.     }  
    16. }  
    17.   
    18. void Quick_sort(int arr[], int low, int high){  
    19.     if(high <= low)return;  
    20.     int i = low - 1, j = high + 1;  
    21.     int key = arr[low];  
    22.     while(true){  
    23.         do{  
    24.             j--;          
    25.         }  
    26.         while(arr[j] > key);  
    27.         do{  
    28.             i++;  
    29.         }  
    30.         while(arr[i] < key);  
    31.         if(i < j)swap(arr[i], arr[j]);  
    32.         else break;  
    33.     }  
    34.     Quick_sort(arr, low, i - 1);  
    35.     Quick_sort(arr, j + 1, high);  
    36. }  
    37.   
    38. int num[100000 + 5];  
    39.   
    40. int main(){  
    41. //  ifstream cin("data.txt");  
    42.     srand((unsigned)time(NULL));  
    43.     int n;  
    44.     cin >> n;  
    45.     for(int i = 0; i < n; i++){  
    46.         cin >> num[i];  
    47.     }  
    48.     disrupt(num, n);  
    49.     Quick_sort(num, 0, n - 1);  
    50.     for(int i = 0; i < n; i++){  
    51.         cout << num[i] << " ";  
    52.     }   
    53.     return 0;  
    54. }  
  • 相关阅读:
    清除某个数据库的所有数据库连接的存储过程
    IIS的Windows集成身份验证总结
    新项目的页面不要直接从PageBase继承
    安装Win2003 SP1遇到拒绝访问
    ASP.NET2.0站点跨服务器访问Sql Sever 2005 Reporting Service
    当CodeSmith不在时,续……
    Web讯雷导致IIS无法启动的问题
    Intro to eDiscovery in SharePoint, Exchange, and Lync 2013
    微软云平台
    团队开发博客
  • 原文地址:https://www.cnblogs.com/peichaoL/p/12436791.html
Copyright © 2020-2023  润新知