荷兰国旗问题
问题一
给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)。
问题二(荷兰国旗问题)
给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)。
void HelanFlag(int *arr,int n,int num){ //num相当于枢轴pivot
int i = 0,left = -1,right = n; //left是左侧小于num的数的右边界,right同理
while(i < right){
if(arr[i] < num){
swap(arr[i],arr[left+1]);
++left;
++i;
}else if(arr[i] == num){
++i;
}else{
swap(arr[i],arr[right-1]);
--right;
}
}
}
快排1.0
每次partition的时候都用最后一个数(或第一个数)作为pivot进行划分,运用荷兰国旗问题进行划分
void QuickSort(int *arr,int n){
int pivot = arr[n-1]; //每次选最后一个元素作为划分值
int left = -1,right = n-1,i = 0;
if(i >= right) return;
while(i < right){
if(arr[i] < pivot){
swap(arr[i],arr[left+1]);
++i;
++left;
}else if(arr[i] > pivot){
swap(arr[i],arr[right-1]);
--right;
}else{
++i;
}
}
swap(arr[i],arr[n-1]);
QuickSort(arr,left+1);
QuickSort(arr+i+1,n-right-1);
}
此时最坏的时间复杂度是O(n^2),分析原因是因为每次取得枢纽都可能太偏了,我们设想,如果对于任意给定的待排序序列都能等概率的使枢纽取在中间位置就可以满足T(N)=2T(N/2)+O(N),也就是说时间复杂度是O(nlogn),此时就需要引入随机数
void QuickSort(int *arr,int n){
int left = -1,right = n-1,i = 0;
if(i >= right) return;
int p = rand() % n;
swap(arr[p],arr[n-1]); //将随机选的数与最后一个数交换,剩下的过程就和1.0几乎一样
int pivot = arr[n-1];
while(i < right){
if(arr[i] < pivot){
swap(arr[i],arr[left+1]);
++i;
++left;
}else if(arr[i] > pivot){
swap(arr[i],arr[right-1]);
--right;
}else{
++i;
}
}
swap(arr[i],arr[n-1]);
QuickSort(arr,left+1);
QuickSort(arr+i+1,n-right-1);
}
int main(){
srand((unsigned)time(NULL)); //随机数发生器
int arr[10] = {9,8,7,6,5,4,3,2,1,0};
QuickSort(arr,10);
for(int i = 0;i < 10;++i){
cout<<arr[i]<<" ";
}
}
将所有可能的情况累加,再求数学期望,最后可以证明,这种方法的时间复杂度为O(nlogn)。
另:快排的平均空间复杂度是O(logn),最差是O(n)。迭代来写,这个空间也省不了,需要自己开。