zoukankan      html  css  js  c++  java
  • luogu_P1177 【模板】快速排序 (快排和找第k大的数)

    【算法】

      选取pivot,然后每趟快排用双指针扫描(l,r)区间,交换左指针大于pivot的元素和右指针小于pivot的元素,将区间分成大于pivot和小于pivot的

    【注意】

      时间复杂度取决于pivot的选取是否能把(l,r)区间分成长度相等的两个子区间。

      最优:O(nlogn)  最差:O(n2)

      问题解决:

    1. 版本一:pivot选择区间中间的元素可以解决数组本身就已经排好序的问题,但是无法解决数组中每个元素均相等(第五个点tle)
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 1e5;
     4 int n,p,i,j;
     5 int a[maxn];
     6 void quick_sort(int l,int r)
     7 {
     8     if(l>r) return;
     9     i = l, j = r;
    10     //swap(a[l], a[(l+r)>>1]); ------pivot选区间中间的元素
    11     while(i < j) {//i和j相等时停下来
    12         while(a[j]>=a[l] && i < j) j--; //先右再左很关键!若右指针和左指针相遇则此时左指针指向pivot或小于pivot的元素(前一次有交换),若左指针和右指针相遇,则此时
    13         while(a[i]<=a[l] && i < j) i++; //右指针应当已经寻找到的小于pivot的元素;若先左再右,则反过来了。pivot的位置会出错。
    14         if(i<j) swap(a[i],a[j]);
    15     }
    16     swap(a[l],a[j]);
    17     quick_sort(l,i-1);
    18     quick_sort(i+1,r);
    19 }
    20 int main()
    21 {
    22     cin>>n;
    23     for(int i = 1; i <= n; i++)
    24         cin>>a[i];
    25     quick_sort(1,n);
    26     for(int i = 1; i <= n; i++)
    27         cout << a[i] << " ";
    28     return 0;
    29 }

        2、版本二:先判断是否有序,若有序则结束,若无序再按原方法。

        3、版本三:每次分成两个子区间,左区间小于等于pivot,右区间大于等于pivot,但不一定确定好pivot的位置,但最终区间长度为2或3的时候必定能确定好

            ------------------------感觉这种要好写一点,理解了之后,其实都是细节------------------------

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 1e5;
     4 int n,p,i,j;
     5 int a[maxn];
     6 void quick_sort(int l,int r)
     7 {
     8     int pivot = a[(l+r)>>1]; 
     9     i = l, j = r;
    10     while(i <= j) { //直到i>j为止,就算数组元素均相等也会向前推进
    11         while(a[i] < pivot) i++; 
    12 while(a[j] > pivot) j--; 13 if(i <= j) { 14 swap(a[i],a[j]); 15 i++, j--; 16 } 17 } 18 if(i < r) quick_sort(i,r); 19 if(j > l) quick_sort(l,j); 20 } 21 int main() 22 { 23 cin>>n; 24 for(int i = 1; i <= n; i++) 25 cin>>a[i]; 26 quick_sort(1,n); 27 for(int i = 1; i <= n; i++) 28 cout << a[i] << " "; 29 return 0; 30 }

        4、找第k大的数:分治法类似快排的方法,平均复杂度O(n)【1+2+4+。。。+n/2+n】按版本三的话不太好写,就按版本一来吧:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int maxn = 1e5;
     4 int n,k,i,j;
     5 int a[maxn];
     6 int quick_find(int l,int r,int k)
     7 {
     8     int pivot = a[(l+r)>>1], rec = 0;
     9     i = l, j = r;
    10     swap(a[(l+r)>>1], a[l]);
    11     while(i < j) {
    12         while(a[j] >= pivot && i < j) j--, rec++;
    13         while(a[i] <= pivot && i < j) i++;
    14         if(i < j) swap(a[i],a[j]);
    15     }
    16     swap(a[i],a[l]);
    17     if(k == rec + 1) return a[i];
    18     else if(k <= rec) return quick_find(i+1,r,k);
    19     else return quick_find(l, i-1, k-rec-1);
    20 
    21 }
    22 int main()
    23 {
    24     cin>>n>>k;
    25     for(int i = 1; i <= n; i++)
    26         cin>>a[i];
    27     cout<<quick_find(1,n,k)<<endl;
    28     return 0;
    29 }

     

  • 相关阅读:
    个性实用的SQL语句
    SiteMesh简介
    oracle基本操作
    java项目中获得不同状态下的磁盘根目录和相对目录。
    linux下安装weblogic 10.3.2.0 及mysql数据源的配置
    SQL Serve 查询所有可用的数据库语句
    [传智播客学习日记]简单工厂模式计算器案例
    [传智播客学习日记]SqlHelper与DataSet
    [传智播客学习日记]序列化、XML序列化与深拷贝操作
    [传智播客学习日记]10月18日第一天正式上课
  • 原文地址:https://www.cnblogs.com/Willendless/p/9310090.html
Copyright © 2011-2022 走看看