luogu_P1177 【模板】快速排序 (快排和找第k大的数)
【算法】
选取pivot,然后每趟快排用双指针扫描(l,r)区间,交换左指针大于pivot的元素和右指针小于pivot的元素,将区间分成大于pivot和小于pivot的
【注意】
时间复杂度取决于pivot的选取是否能把(l,r)区间分成长度相等的两个子区间。
最优:O(nlogn) 最差:O(n2)
问题解决:
- 版本一: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 }