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 }

 

 

 

转载于:https://www.cnblogs.com/Willendless/p/9310090.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值