“这是我参与更文挑战的第17天,活动详情查看: 更文挑战”
上一篇是数据结构与算法新手入门第五篇,本篇是数据结构与算法新手入门第六篇,快来体验一下算法的魅力吧!
快速排序
推演1
以数组最后一个元素为参照物,数组中小于等于它的数移动到数组的左边。
例如:[3, 5, 2, 4, 8, 9, 3, 4] -> [3, 2, 4, 3, 4, 9, 5, 8]
思路:定义一个左边区域,开始在数组第一个元素位置前,即lessEqualR = -1,指针index指向数组第一个元素位置,即index = 0,如果index指向的数小于等于数组最后一个数,则左边区域向前移动一位,lessEqualR与index交换位置后,index向前移动一位。如果index指向的数大于数组最后一个数,则只移动index。
public class Code01_PartitionAndQuickSort {
public static void splitNum(int[] arr) {
int lessEqualR = -1;
int index = 0;
int N = arr.length - 1;
while (index <= N) {
if (arr[index] <= arr[N]) {
swap(arr, ++lessEqualR, index++);
} else {
index++;
}
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] arr = {3, 5, 2, 4, 8, 9, 3, 4};
splitNum(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
推演2
以数组最后一个元素为参照物,数组中小于它的数在左边,等于它的数在中间,大于它的数在右边。
例如:[3, 5, 2, 4, 8, 9, 3, 4] -> [3, 3, 2, 4, 4, 8, 5, 9]
思路:定义一个左边区域,初始位置lessR = -1,一个右边区域,初始位置moreL = N - 1,指针index指向数组第一个元素位置,index = 0,如果index指向的数比数组中最后一个数小,则放到左边区域,如果index指向的数比数组中最后一个数大,则放到右边区域,如果index指向的数等于数组中最后一个数,则不交换。
public class Code01_PartitionAndQuickSort {
public static void splitNum(int[] arr) {
int N = arr.length;
int lessR = -1;
int index = 0;
int moreL = N - 1;
while (index < moreL) {
if (arr[index] < arr[N - 1]) {
swap(arr, ++lessR, index++);
} else if (arr[index] > arr[N - 1]) {
swap(arr, --moreL, index);
} else {
index++;
}
}
swap(arr, moreL, N - 1);
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] arr = {3, 5, 2, 4, 8, 9, 3, 4};
splitNum(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
分区推演
把数组arr[L...R]范围上,划分,左部分、中间部分、右部分。左部分的数都比arr[R]小,中间部分的数等于arr[R],右部分的数都大于arr[R],返回新数组,新数组的长度等于2,第一个元素代表左部分的右边界,第二个元素代表右部分的左边界。下次基于这个开始新一轮的partition划分。
// arr[L...R]范围上,拿arr[R]做划分值,
// L....R < = >
public static int[] partition(int[] arr, int L, int R) {
int lessR = L - 1;
int moreL = R;
int index = L;
while (index < moreL) {
if (arr[index] < arr[R]) {
swap(arr, ++lessR, index++);
} else if (arr[index] > arr[R]) {
swap(arr, --moreL, index);
} else {
index++;
}
}
swap(arr, moreL, R);
return new int[]{lessR + 1, moreL};
}
递归实现
public class Code01_PartitionAndQuickSort {
// arr[L...R]范围上,拿arr[R]做划分值,
// L....R < = >
public static int[] partition(int[] arr, int L, int R) {
int lessR = L - 1;
int moreL = R;
int index = L;
while (index < moreL) {
if (arr[index] < arr[R]) {
swap(arr, ++lessR, index++);
} else if (arr[index] > arr[R]) {
swap(arr, --moreL, index);
} else {
index++;
}
}
swap(arr, moreL, R);
return new int[]{lessR + 1, moreL};
}
public static void process(int[] arr, int L, int R) {
if (L >= R) {
return;
}
int[] equalE = partition(arr, L, R);
process(arr, L, equalE[0] - 1);
process(arr, equalE[1] + 1, R);
}
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
process(arr, 0, arr.length - 1);
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
int[] arr = {3, 5, 2, 4, 8, 9, 3, 4};
quickSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
非递归实现
思路:将待处理的arr[L...R],抽象为一个Job,任务封装了待处理的左部分,右部分。
public class Code01_PartitionAndQuickSort {
// arr[L...R]范围上,拿arr[R]做划分值,
// L....R < = >
public static int[] partition(int[] arr, int L, int R) {
int lessR = L - 1;
int moreL = R;
int index = L;
while (index < moreL) {
if (arr[index] < arr[R]) {
swap(arr, ++lessR, index++);
} else if (arr[index] > arr[R]) {
swap(arr, --moreL, index);
} else {
index++;
}
}
swap(arr, moreL, R);
return new int[]{lessR + 1, moreL};
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
Stack<Job> stack = new Stack<>();
stack.push(new Job(0, arr.length - 1));
while (!stack.isEmpty()) {
Job cur = stack.pop();
int[] equals = partition(arr, cur.L, cur.R);
if (equals[0] > cur.L) { // 有 < 区域
stack.push(new Job(cur.L, equals[0] - 1));
}
if (equals[1] < cur.R) { // 有 > 区域
stack.push(new Job(equals[1] + 1, cur.R));
}
}
}
public static class Job {
public int L;
public int R;
public Job(int l, int r) {
L = l;
R = r;
}
}
public static void main(String[] args) {
int[] arr = {3, 5, 2, 4, 8, 9, 3, 4};
quickSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
总结
本篇介绍了快速排序的思路,至于什么是快速排序,大家可以先普及下。快速排序的递归实现及非递归实现的思路有没有引人耳目!嘻嘻!
欢迎大家关注公众号(MarkZoe)互相学习、互相交流。