快排Java代码实现(Quick Sort)

1.  快排算法思路

基本思想:通过一趟快速排序待排数组分割成独立的两份部分; 其中一部分数组的值均比另一部分数组的值小,则可分别对着两部分数组继续进行排序,以达到整个序列有序。

快排的平均时间复杂度为n*log(n),最坏的时间复杂度为 n^2。

一趟快速排序:首先先选一个值(通常选择数组第一个值)作为枢轴,然后按下述原则重新排列其余的值,将数组中所有小于枢轴的值放在枢轴前面,数组中所有大于枢轴的值放在枢轴后面。将枢纽最后的位置作为分界线,将数组分成两部分(两部分均不包含枢轴),这个过程称作一趟快速排序。

一趟快速排序的具体做法

1.  设两个指针 low 和 high , 他们的初始值分别为数组开始的下标 start,数组结束的下标end

2.  枢轴值为 pivotKey

3.   则首先从 high 所指位置向前搜索,搜索到第一个小于 pivotKey 的 值,然后将这个值和  pivotKey 互相交换。

4.  从 low 所指位置向后搜索,搜索到第一个大于 pivotKey 的 值,然后将这个值和  pivotKey 互相交换。

5.  重复前两步操作(3,4),直至 low == high 。

2.  Java 代码实现

完全按照上面的思路的 Java 代码如下:

package sort;

/**
 * 快速排序(Quick Sort) Java代码实现
 * 快排时间复杂度:n*log(n)
 */

public class MySort {

    public static void main(String args[]) {
        int[] arr = new int[]{49, 38, 65, 97, 76, 13, 27};
        MySort mySort = new MySort();

        System.out.print("排序前的数组: ");
        PrintArray(arr, 0, arr.length-1);
        mySort.quickSort(arr, 0, arr.length-1);

        System.out.print("排序后的结果: ");
        PrintArray(arr, 0, arr.length-1);
    }

    /**
     * 对数组 arr 下标从 start 到 end 的内容进行排序
     * @param arr:待排序数组
     * @param start:开始的下标
     * @param end:结束的下标
     */
    public static void quickSort(int[] arr, int start, int end) {
        if(start >= end) {
            return;
        }

        // 1.  设两个指针 low 和 high ,他们的初始值分别为数组开始的下标 start,数组结束的下标end
        int low = start;
        int high = end;

        // 2.  枢轴值为 pivotKey
        int pivotKey = arr[start];

        // 5. 重复前两步操作(3,4),直至 low == high
        while (low<high) {

            // 3. 首先从 high 所指位置向前搜索,搜索到第一个小于 pivotKey 的 值,然后将这个值和  pivotKey 互相交换
            while (low<high && arr[high]>=pivotKey) {
                --high;
            }
            int temp1 = arr[low];
            arr[low] = arr[high];
            arr[high] = temp1;


            // 4. 从 low 所指位置向后搜索,搜索到第一个大于 pivotKey 的 值,然后将这个值和  pivotKey 互相交换。
            while (low<high && arr[low]<=pivotKey) {
                ++low;
            }
            temp1 = arr[low];
            arr[low] = arr[high];
            arr[high] = temp1;
        }

        // 对 小于枢轴值的那部分数组值 进行快排
        quickSort(arr, start, low-1);
        // 对 大于枢轴值的那部分数组值 进行快排
        quickSort(arr, low+1, end);
    }

    /**
     *输出数组中的值
     * @param arr:数组
     * @param start:数组开始的下标
     * @param end:数组结束的下标
     */
    public static void PrintArray(int[] arr, int start, int end) {

        for (int i=start; i<=end; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println("");
    }
}

运行可得 :

                      

3.  简单的优化

进行一次数值交换,如 :temp1 = arr[low]; arr[low] = arr[high]; arr[high] = temp1,需要三次赋值,temp1 = arr[low]; arr[high] = temp1 这两次赋值其实是多余的,因为 当 low == high , 也就是最终的位置 low ,就是枢轴值的位置,我们只需要在一次快排结束后将枢轴值放到 low 位置就可以了。Java源码如下。

package sort;

/**
 * 快速排序(Quick Sort) Java代码实现
 * 快排时间复杂度:n*log(n)
 */

public class MySort {

    public static void main(String args[]) {
        int[] arr = new int[]{49, 38, 65, 97, 76, 13, 27};
        MySort mySort = new MySort();

        System.out.print("排序前的数组: ");
        PrintArray(arr, 0, arr.length-1);
        mySort.quickSort(arr, 0, arr.length-1);

        System.out.print("排序后的结果: ");
        PrintArray(arr, 0, arr.length-1);
    }

    /**
     * 对数组 arr 下标从 start 到 end 的内容进行排序
     * @param arr:待排序数组
     * @param start:开始的下标
     * @param end:结束的下标
     */
    public static void quickSort(int[] arr, int start, int end) {
        if(start >= end) {
            return;
        }

        // 1.  设两个指针 low 和 high ,他们的初始值分别为数组开始的下标 start,数组结束的下标end
        int low = start;
        int high = end;

        // 2.  枢轴值为 pivotKey
        int pivotKey = arr[start];

        // 5. 重复前两步操作(3,4),直至 low == high
        while (low<high) {

            // 3. 首先从 high 所指位置向前搜索,搜索到第一个小于 pivotKey 的 值,然后将这个值和  pivotKey 互相交换
            while (low<high && arr[high]>=pivotKey) {
                --high;
            }
            arr[low] = arr[high];


            // 4. 从 low 所指位置向后搜索,搜索到第一个大于 pivotKey 的 值,然后将这个值和  pivotKey 互相交换。
            while (low<high && arr[low]<=pivotKey) {
                ++low;
            }
            arr[high] = arr[low];
        }

        // 一次快排结束后将枢轴值放到 low 位置
        arr[low] = pivotKey;

        // 对 小于枢轴值的那部分数组值 进行快排
        quickSort(arr, start, low-1);
        // 对 大于枢轴值的那部分数组值 进行快排
        quickSort(arr, low+1, end);
    }

    /**
     *输出数组中的值
     * @param arr:数组
     * @param start:数组开始的下标
     * @param end:数组结束的下标
     */
    public static void PrintArray(int[] arr, int start, int end) {

        for (int i=start; i<=end; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println("");
    }
}

运行截图 :

4.  优化措施

优化最坏的情况:在选择枢轴,取数组的第一个元素、中间的那个元素、最后一个元素的中位数作为枢轴。

优化最好的情况:添加两个 布尔类型 变量,如果 指针low 从低端向中间的移动过程中没有交换记录,则不需要对枢轴左部分的元素排序;如果 指针high 从高端向中间的移动过程中没有交换记录,则不需要对枢轴右部分的元素排序,这样就可能达到n的时间复杂度。

5.  参考文献

数据结构 -  严蔚敏、吴伟民 -  清华大学出版社

快速排序(Quick Sort)是一种高效的排序算法,其基本思想是通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,直到整个序列有序。以下是使用 Java 实现快速排序的基本步骤: 1. **选择基准值** (Pivot): 通常选取数组的第一个元素作为基准值。 2. **分区操作** (Partitioning): 将数组分为两个区域,左边的所有元素都小于等于基准值,右边的所有元素都大于基准值。可以使用双指针法,一个指针从左开始,另一个从右开始,找到第一个大于基准值的数放到左边,找到第一个小于等于基准值的数放到右边,交换这两个位置的数。 3. **递归排序** (Recursion): 对左右两个区域分别递归地应用上述过程,直到每个区域只剩下一个元素或为空。 4. **合并结果** (Combining Results): 当所有递归调用完成后,数组就被排序了。 以下是一个简单的 Java 快速排序示例: ```java public class QuickSort { public void quickSort(int[] arr, int low, int high) { if (low < high) { // 选择基准值 int pivotIndex = partition(arr, low, high); // 递归排序左右两个子区间 quickSort(arr, low, pivotIndex - 1); quickSort(arr, pivotIndex + 1, high); } } private int partition(int[] arr, int low, int high) { // 选择第一个元素作为基准 int pivotValue = arr[low]; while (low < high) { // 找到第一个大于基准的元素并将其移到左边 while (low < high && arr[high] >= pivotValue) { high--; } arr[low] = arr[high]; // 找到第一个小于等于基准的元素并将其移到右边 while (low < high && arr[low] <= pivotValue) { low++; } arr[high] = arr[low]; } // 将基准值放在最终的位置 arr[low] = pivotValue; return low; } // 测试函数 public static void main(String[] args) { int[] arr = {9, 7, 5, 11, 12, 2, 14, 3, 10}; QuickSort quickSort = new QuickSort(); quickSort.quickSort(arr, 0, arr.length - 1); for (int num : arr) { System.out.print(num + " "); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值