新手入门篇-快速排序的新颖实现方式

283 阅读3分钟

“这是我参与更文挑战的第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。

image.png

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指向的数等于数组中最后一个数,则不交换。

image.png

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)互相学习、互相交流。