快速排序

1、快速排序思想:

  快速排序主要利用分治和递归的思想,例如,将一个数组{2,5,10,1,0,7}排序。首先选取其第一个元素2作为基准,将<2的元素移动到其左边,将>=2的元素移动到其右边(其中等于2放左放右都可以),此过程称为一次分区,可以得到{0,1,2,10,5,7}。经过一次分区后,数组就分成了两个部分,左边小于2,右边大于等于2,并且局部有序了一点。因此可以继续分别对其左右分区{0,1}和{10,5,7}再分别进行快排,不断的迭代,直至完全有序。

  过程解析:写两个quickSort方法,一个是主程序调用入口,另一个是重载方法,重载的参数是迭代排序的范围。主要需要实现的partition分区方法,改方法主要利用头尾指针交替寻找比基准节点大或者小的数,并交换两个指针的值,以达到分区的目的。

2、代码实现

import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {2, 5, 10, 1, 0, 7};
        System.out.println(Arrays.toString(arr));
        QuickSort quickSort = new QuickSort();
        quickSort.quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public void quickSort(int[] arr) {
        int start = 0;
        int end = arr.length - 1;
        quickSort(start, end, arr);
    }

    public void quickSort(int start, int end, int[] arr) {
        if (start < end) {
            int index = partition(start, end, arr);
            quickSort(start, index - 1, arr);
            quickSort(index + 1, end, arr);
        }
    }

    public int partition(int start, int end, int[] arr) {
        int k = arr[start];
        while (start < end) {
            while (arr[end] >= k && start < end) {
                end--;
            }
            if (start < end) {
                arr[start] = arr[end];
                start++;
            }
            while (arr[start] < k && start < end) {
                start++;
            }
            if (start < end) {
                arr[end] = arr[start];
                end--;
            }
        }
        arr[start] = k;
        int index = start;
        return index;
    }
}
import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {2, 5, 10, 1, 0, 7};
        System.out.println(Arrays.toString(arr));
        QuickSort quickSort = new QuickSort();
        quickSort.quickSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    //快排方法
    public void quickSort(int[] arr) {
        int start = 0;
        int end = arr.length - 1;
        quickSort(start, end, arr);
    }

    //快排方法重载,带上数组应该排序部分的首尾指针,每次分区完成,都要缩小范围
    public void quickSort(int start, int end, int[] arr) {
        //递归,递归的终止条件,不断的分区排序,知道不能再分区为止
        if (start < end) {
            //将数组继续拆分成两个分区,继续进行分区
            int index = partition(start, end, arr);
            //将数组继续拆分成两个分区,继续进行分区
            quickSort(start, index - 1, arr);
            quickSort(index + 1, end, arr);
        }
    }

    //分区方法,局部排序
    public int partition(int start, int end, int[] arr) {
        //选择数组的第一个元素为基准点,并将基准点值保存到k中
        int k = arr[start];
        //将小于基准点的元素移动至数组的左边,大于的移动至右边
        //循环终止条件,只要有头尾指针的,一般都是这个,其实遍历完了整个数组就终止了
        while (start < end) {
            //从数组的右边开始,找比基准点小的数,将指针指向该数
            //右边开始遍历,找到第一个即停止
            while (arr[end] >= k && start < end) {
                end--;
            }
            //上面指针指向了比基准点小的元素,接下来就将该元素移动到基准点的左侧
            //放置的位置是头指针指向的位置,头指针向后移动一位
            if (start < end) {
                arr[start] = arr[end];
                start++;
            }

            //同理,从左至右找比基准点大的元素,找到了循环就先暂停
            while (arr[start] < k && start < end) {
                start++;
            }
            //交换位置,将该值交换到尾指针指向的位置,因为尾指针的值已经赋给了之前的头指针
            //尾指针向前移位
            if (start < end) {
                arr[end] = arr[start];
                end--;
            }

            //如此反复循环,不断将遇到的第一个符合条件的元素交换至对应侧
        }
        //记得将基准点元素的值还回去,循环结束指针指向的位置就是基准点的最终位置
        arr[start] = k;
        //记录循环结束后头尾指针的位置,头尾指针肯定在一个位置上,因为循环结束了start=end
        int index = start;
        //返回该位置
        return index;
    }
}

3、时间空间复杂度

时间复杂度:平均时间复杂度为O(nlogn),最坏时间复杂度O(n^2)。

空间复杂度:每次递归传参left,和right,平均递归次数是log(n)次,所以平均空间复杂度是O(log(n))。最坏的情况是O(n)(初始是逆序的情况)。

原文地址:https://www.cnblogs.com/guoyu1/p/11871740.html