目录
问题描述
- 给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)
分析过程
我们可以把这个模型抽象为:给定一个规范值(value)
等于value的放中间(白色)小于value的放左边(红)大于value的放右边(蓝)
设置一个小于区,一个大于区,对于index下标对应的值有如下的规则:
①如果<value则index所指的元素与小于区右边的前一个元素做交换 小于区右扩,index++
②如果=value则index++
③如果>value则让index所指的元素与大于区左边的前一个元素做交换 大于区右扩(此时index指向的是后面换过来的元素,该元素没有被判断过所以index不++)
当index==大于区的左界的时候 此时数组划分为了三块,<区 =区 >区 正如荷兰国旗一样分为三种颜色 红 白 蓝,但是注意了还没有结束
最后还要把规范值(相当于是=value的值)与大于区的左边界的第一个元素进行互换才行.
*/
代码实现
import java.util.Arrays;
import java.util.Stack;
public class Code2_PartitionTestAndQuickSortAndRandomQuickSort {
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static int[] partition(int[] arr,int l,int r){
if(l>r){
return new int []{-1,-1};
}
if(l==r){
return new int[]{l,r};
}
//l<r
int lessR=l-1;
int moreL=r;
int index=l;
while(index<moreL){
if(arr[index]==arr[r]){
index++;
}else if(arr[index]<arr[r]){
swap(arr,++lessR,index++);
}else{
swap(arr,--moreL,index);
}
}
swap(arr,r,moreL);
int equalL=lessR+1;
int equalR=moreL;
return new int[]{equalL,equalR};
}
public static void quickSort(int[] arr){
if(arr==null ||arr.length<2){
return;}
process(arr,0,arr.length-1);
}
public static void process(int[] arr,int l,int r){
if(l>=r){
return;
}
int[] partition = partition(arr, l, r);
process(arr,l,partition[0]-1);
process(arr,partition[1]+1,r);
}
public static void randomQuickSort(int[] arr){
if(arr==null || arr.length<2){
return;
}
process1(arr,0,arr.length-1);
}
public static void process1(int[] arr,int l,int r){
if (l >= r) {
return;
}
int[] partition = partition(arr, l, r);
process1(arr,l,partition[0]-1);
process1(arr,partition[1]+1,r );
}
public static class Info{
int left;
int right;
public Info(int left, int right) {
this.left = left;
this.right = right;
}
}
//非递归的方式实现随机快排(用栈代替系统栈)
public static void randomQuickSort2 (int[] arr){
if(arr==null || arr.length<2){
return ;
}
int N=arr.length;
swap(arr,N-1,(int)(Math.random()*N));
int[] partition = partition(arr, 0, N - 1);
Info infoLess=new Info(0,partition[0]-1);//小于区的区间信息
Info infoMore=new Info(partition[1]+1,N-1);
Stack<Info> stack=new Stack();
stack.push(infoLess);
stack.push(infoMore);
while(!stack.isEmpty()){
Info info = stack.pop();
if(info.left<info.right){
swap(arr,info.left+(int)(Math.random()*(info.right-info.left+1)),info.right);
int[] partition1 = partition(arr, info.left, info.right);
infoLess=new Info(info.left,partition1[0]-1);
infoMore=new Info(partition1[1]+1,info.right);
stack.push(infoLess);
stack.push(infoMore);
}
}
}
}
编写对数器
public static int[] generateRandomArray(int maxSize, int maxValue) {
int[] arr = new int[(int) ((maxSize + 1) * Math.random())];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int) ((maxValue + 1) * Math.random()) - (int) (maxValue * Math.random());
}
return arr;
}
public static int[] copyArray(int[] arr) {
if (arr == null) {
return null;
}
int[] res = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
res[i] = arr[i];
}
return res;
}
public static boolean isEqual(int[] arr1, int[] arr2) {
if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)) {
return false;
}
if (arr1 == null && arr2 == null) {
return true;
}
if (arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}
public static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int testTime = 10000;
int maxSize = 10;
int maxValue = 100;
boolean succeed = true;
System.out.println("test begin");
for (int i = 0; i < testTime; i++) {
int[] arr1 = generateRandomArray(maxSize, maxValue);
int[] arr2 = copyArray(arr1);
randomQuickSort(arr1);
randomQuickSort2(arr2);
if (!isEqual(arr1, arr2)) {
succeed = false;
printArray(arr1);
printArray(arr2);
break;
}
}
System.out.println("test end");
System.out.println("测试" + testTime + "组是否全部通过:" + (succeed ? "是" : "否"));
}