目录
荷兰国旗问题
描述
荷兰国旗有三种条纹构成,自上到下条纹的颜色依次为红、白、蓝。现有若干红、白、蓝三种颜色的条纹序列,要将它们重新排列使所有相同颜色的条纹在一起。本问题要求将所有红色的条纹放最上边、所有白色的条块放中间、所有蓝色的条纹放最下边。(如下所示)
实际上可以把题目简化为编程题目:
给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)。
题目思路:实际上类似于快排的思想,设3个移动变量,假设
int arr[10] = {2,5,1,3,4,9,5,8,5,7};
num = 5; //中间数
假设三个指针,分别指向数组的最左侧减一,最右侧加1,以及数组最左端。
开始排序:
1.当 i 指向 第0位 时,发现 arr[0] 小于 num(也就是5), 那么便 (L-1)+1 = L 位与 第 i 位进行交换,并且各向前移动一位,变成如下:(由于L位和 i 位恰好都为 0 ,所以发生自身与自身交换)
2.当 i 指向 第1位 时,发现 arr[1] 等于 num, 那么 i 向前移动一位,由于左边不交换,L的位置不动,变成如下:
3.当 i = 2 时,发现 arr[2] 小于 num, 那么便 L+1 位与 第 i 位进行交换,并且各向前移动一位,变成如下:
4. i = 3, i = 4 都是小于 num,所以操作跟步骤3 一样,得到如下。此时 i = 5 ,arr[5] = 9 > num,所以arr[i] 与 arr[(R+1)-1]进行交换,这里注意,由于交换以后原来的arr[(R+1)-1]的值并不一定小于等于num,所以我们不能让 i 前进一步,必须继续判断 arr[i] 与 arr[R - 1] 的值,进行交换,以此类推,直到不交换为止,图示如下:
5.这里到最后一步,i = 7,arr[7] = 8 > num ,那么便使得 arr[7] 与 arr[R - 1]交换,这里可以看出 R - 1 = 7,所以需要停止搜索了,终止的条件就是 i 与右边指针所指相等。
代码很简单如下:
void mySwap(int * a, int *b){
if(a != b){
(*a) ^= (*b);
(*b) ^= (*a);
(*a) ^= (*b);
}
}
void mySort(int *arr, int L,int R, int num){
int i = 0;
while(i < R){
if(arr[i] < num)
mySwap(&arr[++L],&arr[i]);
else if(arr[i] > num){
mySwap(&arr[--R], &arr[i]);
continue;
}
i++;
}
}
int main()
{
int arr[10] = {2,5,1,3,4,9,5,8,5,7};
mySort(arr,-1,10,5);
for(int i =0; i<10; i++){
cout<<arr[i]<<" ";
}
return 0;
}
快排改进(随机快排)
通过上面的思想实际上我们可以对快排进行改进,快排的思想是拿取一个数字然后把其定位到正确的位置;但是实际上数组中不一定只有一个大小为拿取数大小的数字,可能有一批数字均相等,此时我们便可以利用上述问题的解决方法进改进。
- 把数组分成三块小于num,等于num,大于num;之后进行递归时只要对小于和大于两边的数组进行排序即可,这样效率也会提升。
- 其次,由于在快排中,我们通常拿取的比较数字一般是首个或者末尾,但是这样如果遇到 顺序数列 {5,4,3,2,1}或者{1,2,3,4,5},效率会大大降低,使得时间复杂度可能降为O(N^2);为了提高效率,我们可以采取随机拿取某个数来进行比较,这个方法数学推导也证明了期望时间复杂度为 O(NlogN)。
代码如下:
void mySwap(int * a, int *b){
if(a != b){
(*a) ^= (*b);
(*b) ^= (*a);
(*a) ^= (*b);
}
}
void quickSort2(int *arr, int left, int right){
if(left < right){
mySwap(&arr[left + rand()%(right-left+1)],&arr[right]); //随机拿取
int i = left, L = left - 1, R = right;
while(i < R){
if(arr[i] < arr[right])
mySwap(&arr[++L],&arr[i++]);
else if(arr[i] > arr[right])
mySwap(&arr[--R],&arr[i]);
else
i++;
}
mySwap(&arr[R],&arr[right]);//arr[right]最后进行交换,前面不变
quickSort2(arr,left,L);
quickSort2(arr,R+1,right);
}
}