目录
一.荷兰国旗
1.题目描述
给定一个数组arr和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。
要求额外空间复杂度为O(1),时间复杂度为O(N)。
2.分析思路
初始化less=-1,more=len(arr),当前位置为cur=0。
设该过程为partition。设数组为(arr,l,r),0~less为小于num区域,more右为大于等于num区域。
循环结束的条件,cur碰上num。如图1。
(1)cur<num,当前数和小于区域下一个数交换,小于区域扩下个位置。cur跳下一个。
swap(arr, ++less, l++);
(2)cur=num,cur直接跳下一个。
cur++;
(3)cur>num,和大于区域前一个数交换,大于区域向左扩一个位置。cur停在原地(当前数不变)。
swap(arr, --more, cur);
3.实现代码
vector<int> partition(vector<int> &arr,int L ,int R,int,num) {
int less = L- 1;
int more = R+1;
int cur=L;
while (cur < more) {
if (arr[cur] < num) {
swap(arr[++less], arr[L++]);
else if (arr1[cur] > num) {
swap(arr[more--],arr[L]);
}
else {
cur++;
}
}
vector<int> p(2);
p[0] = less + 1; //less+1等于区域第一个数
p[1] = more-1; //more-1等于区域最后一个数
return p; //返回等于区域下标
}
二.快速排序(乱序快排优化版)
1.算法思想
采用分治的思想
- 先从数组中取最后一个数作为基准数。
- 分区过程,将比这个数大的数全放到它的右边,小于它的数全放到它的左边,等于它的放中间。
- 再对小于和大于的左右区间重复第二步,递归结束的条件是L>R。
2.时间复杂度O(N*logN),额外空间复度O(logN),算法不稳定
3.实现代码
void quickSort(vector<int> arr) {
if (arr.empty() || arr.size() < 2) {
return;
}
quickSort(arr, 0, arr.size()- 1);
}
void quickSort(vector<int> arr, int l, int r) {
if (l < r) {
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
//快排中比较的最后一个数随机按概率定
vector<int> p = partition(arr, l, r);
quickSort(arr, l, p[0] - 1); //小于区域递归排序
quickSort(arr, p[1] + 1, r); //大于区域递归排序
}
vector<int> partition(vector<int> &arr,int L ,int R) {
int less = L- 1;
int more = R;
while (L < more) {
if (arr[L] < arr[r]) {
swap(arr[++less], arr[L++]);
}
else if (arr1[L] > arr[r]) {
swap(arr[more--],arr[L]);
}
else {
L++;
}
}
swap(arr[more],arr[r]); //使最右边的数放到等于区域
vector<int> p(2);
p[0] = less + 1; //less+1等于区域第一个数
p[1] = more-1; //more-1等于区域最后一个数
return p; //返回等于区域下标
}
补充:
- 1.swap(arr[more],arr[r]);的原理如图2.
- 2.传统快排如果打偏,算法复杂度O(N2)