随机快速排序

给定一个数组arr,和一个整数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(N)

public static int partition(int[] arr, int L, int R) {
   if (L > R) {
      return -1;
   }
   if (L == R) {
      return L;
   }
   int lessEqual = L - 1;
   int index = L;
   while (index < R) {
      if (arr[index] <= arr[R]) {
         swap(arr, index, ++lessEqual);
      }
      index++;
   }
   swap(arr, ++lessEqual, R);
   return lessEqual;
} 

荷兰国旗问题:

给定一个数组arr,和一个整数num,请把小于num的数放在数组的左边,等于num的数放在中间,大于num的数放在数组的右边,要求额外空间复杂度O(1),时间复杂度O(N) 

public static int[] netherlandsFlag(int[] arr, int L, int R) {
      if (L > R) { // L...R 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;
      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); // <[R]   =[R]   >[R]
      return new int[] { less + 1, more };
   }

在arr[L..R]范围上,进行快速排序的过程:

1)用arr[R]对该范围做partition,<= arr[R]的数在左部分并且保证arr[R]最后来到左部分的最后一个位置,记为M; <= arr[R]的数在右部分(arr[M+1..R])

2)对arr[L..M-1]进行快速排序(递归)

3)对arr[M+1..R]进行快速排序(递归) 因为每一次partition都会搞定一个数的位置且不会再变动,所以排序能完成 

public static void quickSort1(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;
   }
   // L..R partition arr[R] [ <=arr[R] arr[R] >arr[R] ]
   int M = partition(arr, L, R);
   process1(arr, L, M - 1);
   process1(arr, M + 1, R);
}

在arr[L..R]范围上,进行快速排序的过程:

1)用arr[R]对该范围做partition,< arr[R]的数在左部分,== arr[R]的数中间,>arr[R]的数在右部分。假设== arr[R]的数所在范围是[a,b]

2)对arr[L..a-1]进行快速排序(递归)

3)对arr[b+1..R]进行快速排序(递归) 因为每一次partition都会搞定一批数的位置且不会再变动,所以排序能完成 

public static void quickSort2(int[] arr) {
   if (arr == null || arr.length < 2) {
      return;
   }
   process2(arr, 0, arr.length - 1);
}
public static void process2(int[] arr, int L, int R) {
   if (L >= R) {
      return;
   }
   // [ equalArea[0]  ,  equalArea[0]]
   int[] equalArea = netherlandsFlag(arr, L, R);
   process2(arr, L, equalArea[0] - 1);
   process2(arr, equalArea[1] + 1, R);
}

在arr[L..R]范围上,进行快速排序的过程:

1)在这个范围上,随机选一个数记为num,用num对该范围做partition,< num的数在左部分,== num的数中间,>num的数在右部分。假设== num的数所在范围是[a,b]

2)对arr[L..a-1]进行快速排序(递归)

3)对arr[b+1..R]进行快速排序(递归) 因为每一次partition都会搞定一批数的位置且不会再变动,所以排序能完成 

public static void quickSort3(int[] arr) {
   if (arr == null || arr.length < 2) {
      return;
   }
   process3(arr, 0, arr.length - 1);
}

public static void process3(int[] arr, int L, int R) {
   if (L >= R) {
      return;
   }
   swap(arr, L + (int) (Math.random() * (R - L + 1)), R);
   int[] equalArea = netherlandsFlag(arr, L, R);
   process3(arr, L, equalArea[0] - 1);
   process3(arr, equalArea[1] + 1, R);
}

 递归和非递归两种方式写出随机快排

// 快排递归版本
public static void quickSort1(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;
   }
   swap(arr, L + (int) (Math.random() * (R - L + 1)), R);
   int[] equalArea = netherlandsFlag(arr, L, R);
   process(arr, L, equalArea[0] - 1);
   process(arr, equalArea[1] + 1, R);
}
public static class Op {
   public int l;
   public int r;

   public Op(int left, int right) {
      l = left;
      r = right;
   }
}

// 快排非递归版本
public static void quickSort2(int[] arr) {
   if (arr == null || arr.length < 2) {
      return;
   }
   int N = arr.length;
   swap(arr, (int) (Math.random() * N), N - 1);
   int[] equalArea = netherlandsFlag(arr, 0, N - 1);
   int el = equalArea[0];
   int er = equalArea[1];
   Stack<Op> stack = new Stack<>();
   stack.push(new Op(0, el - 1));
   stack.push(new Op(er + 1, N - 1));
   while (!stack.isEmpty()) {
      Op op = stack.pop(); // op.l  ... op.r
      if (op.l < op.r) {
         swap(arr, op.l + (int) (Math.random() * (op.r - op.l + 1)), op.r);
         equalArea = netherlandsFlag(arr, op.l, op.r);
         el = equalArea[0];
         er = equalArea[1];
         stack.push(new Op(op.l, el - 1));
         stack.push(new Op(er + 1, op.r));
      }
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值