快速排序

58 阅读1分钟

递归版本

// 把等于数组最右边的数放中间,大于的全放右边,小于的全放左边
public static int[] netherlandsFlag(int[] arr, int L, int R) {
   // 小于区域指针,这个指针和它左边的所有数都是小于数组最右边的数的
   int less = L - 1;
   // 大于区域指针,这个指针和它右边的所有数都是大于数组最右边的数的
   // 数组最右边的数除外
   int more = R;
   // index遍历数组,直到撞到大于区域为止
   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 };
}

public static void swap(int[] arr, int i, int j) {
   int tmp = arr[i];
   arr[i] = arr[j];
   arr[j] = tmp;
}

// 快排递归版本
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;
   }
   // 把固定的最右边的参考数,换成随机的一个参考数
   //此举可以把时间复杂度从O(N2)变为O(N * logN)
   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));
      }
   }
}