快排和归并排序一样都是分治法思想。
快速排序的主要思想:
将序列分为左右两部分, 使得左边的数都比基准值小,右边的数都比基准值大。递归这个过程,直到不能再分。
那么如何将序列分为左右两部分,以及基准值怎么选取是快排的核心。
先看图:图片来自https://www.cnblogs.com/onepixel/p/7674659.html
快速排序的几种实现方式:
第一种, 左右交叉交换。
基准值取法为 区间i-j的任意值
先从右边找到一个比基准值小的数,然后将基准值和该数换位置
然后从左边找到一个比基准值大的数,然后将基准值和该数换位置
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
int arr[1000005];
int n;
void q_sort(int i, int j){
if(i>=j) return;
int x =i+rand()%(j-i+1); // 随机取一个基准值
int piovt = arr[x];
arr[x] = arr[i];
int low = i;
int high = j;
while(low<high){
while(low<high&&arr[high]>=piovt) --high;
arr[low] = arr[high];
while(low<high&&arr[low]<=piovt) ++low;
arr[high] = arr[low];
}
arr[low] = piovt;
q_sort(i,low-1);
q_sort(low+1,j);
};
int main(){
scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%d",&arr[i]);
}
q_sort(0,n-1);
for(int i = 0; i < n; i++){
i ? printf(" %d",arr[i]) : printf("%d",arr[i]);
}
return 0;
}
第二种:
左右交换
基准值选中间值
将右边比基准值小的数和左边比基准值大的数交换。
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
int arr[1000005];
int n;
void q_sort(int i, int j){
if(i>=j) return;
int piovt = arr[(i+j)/2];
int low = i;
int high = j;
while(low<=high){
while(arr[high]>piovt) --high;
while(arr[low]<piovt) ++low;
if(low<=high){
// cout<<low<<" "<<high<<endl;
swap(arr[high],arr[low]);
--high;
++low;
}
// for(int l = 0; l < n; l++) cout<<arr[l]<<" "; cout<<endl; // 1 3 1 2 5
}
if(i<high)q_sort(i,high);
if(j>low)q_sort(low,j);
};
int main(){
scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%d",&arr[i]);
}
q_sort(0,n-1);
for(int i = 0; i < n; i++){
i ? printf(" %d",arr[i]) : printf("%d",arr[i]);
}
return 0;
}
当存在大量重复数据时,第二种会优于第一种
强烈推荐第二种。