荷兰国旗问题有两种情况: 1)给定一个数x,<= x的整体放在左边,>x的整体放在右边 2)给定一个数x,< x的整体放在左边,= x的整体放在中间,> x的整体放在右边 规定不需要辅助数组,时间复杂度O(N)完成上面的调整 现在先来看第一个情况:
如图所示,我们先划分一个<=区域在左侧,第一个元素的下标位置是i,给定的数为x。现在我们需要对这个数组进行划分 1.当i在3这个位置的时候,i位置和<=区域的下一个位置做交换,此时就是自己跟自己交换。 2.<=区域向右移动,来到3和5之间的位置。 3,i++; 如果现在i来到6位置,发现6大于num,此时<=区域不移动,i++. 下图为最终结果
现在看第二种情况:
如图所示,我们再次进行区域的划分,这次有了<区域和>区域 1.当当前i<num的时候,i和<区域的下一个数做交换,<区域右移,i++ 2.当当前i=num的时候,直接i++ 3,当当前i>num的时候,i位置和>区域的前一个数做交换,>区域左移,i不变 i不变的原因是i是新过来的,此时还没有和numb比较。 当>区域和i撞上的时候,停止。
现在看看代码:
public static void swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// arr[L...R] 玩荷兰国旗问题的划分,以arr[R]做划分值
// <arr[R] ==arr[R] > arr[R]
public static int[] netherlandsFlag(int[] arr, int L, int R) {
if(L > R){
return new int[]{-1,-1};
}
if(L == R){
return new int[]{L,R};
}
int less = L - 1;//左边界
int more = R;//有边界
int index = L;//就是之前的i
while(index < more){
if(arr[index] == arr[R]){
index++;
} else if(arr[index] < arr[R]){
//swap(arr,less + 1,index);
//less++;
//index++;
swap(arr,index++,++less);
} else {
swap(arr,index,--more);
}
}
//将划分值那个数和大于区域的第一个位置做交换
swap(arr,more,R);
//等于区域第一个数: less + 1, 最后一个more
return new int[]{less + 1,more};
}
现在看快排1.0版本
1.0和荷兰国旗问题一样,只不过他是拿最后面的那个数来作为划分值,先看看这个图
第一个表示他的划分值是5,在<=区域都是<=5的,大于区域都是大于5的,现在我们拿大于区的第一个数和最后一个数做交换,就得到了第二个图形的样子。和荷兰国旗的区别就是增加了递归的过程,现在我们需要在<=5区域继续做划分,在 <=5区域的最后一个值当作划分值,然后继续划分,在>5区域的最后一个数当做划分值,继续划分。一直递归下去,总会得到一个有序的集合。 快排2.0版本
2.0版本和荷兰国旗问题的第二个情况类似,如上图所示,划分值还是最后的那个数5,在一次划分的时候出现了5的区域
这张图的意思是在>区域的第一个数和划分值作交换,之后我们就可以得到小于5的区域在一堆,> and 5的区域做递归。总会得到有序的集合。
现在看快排3.0
快排1.0和2.0都有缺陷,就是最坏的时间复杂度是O(n^2),因为我们总是选数组最后一个值作为划分值,总会出现极端的情况,而且概率会比较大,那么快排3.0就是为了解决这个问题的,如上图所示,我们如果在数组中随机找一个点,然后将其对应的元素和数组最后的一个元素进行交换,那么这样的话,我们从数组中随机找到一个划分值从概率上来说会更小,我们省略了数学上的推算,这样的话他的时间复杂度达到了O(N*logN).
public static void quickSort(int[] arr){
if(arr == null || arr.length < 2){
return;
}
quickSort(arr,0,arr.length - 1);
}
public static void quickSort(int[] arr,int L,int R){
if(L < R){
swap(arr,L + (int)(Math.random() * (R - L + 1),R);
int[] p = partition(arr,L,R);//此处数组只有两个元素,表示划分值区域的左边界和有边界
partition(arr,L,p[0] - 1);
partition(arr,p[1] + 1,R);
}
}
public static int[] partition(int[] arr,int L,int R){
int less = L - 1;//<= 区域
int more = R;//>区域
int index = L;//当前数的位置
while(index < more){
if(arr[index] == arr[R]){
index++;
} else if(arr[index] < arr[R]){
swap(arr,index++,++less);
} else {
swap(arr,index,--more);
}
}
swap(arr,more,R);
return new int[]{less+1,more};
}
在有道上写的笔记复制到这里就有点问题