八大排序算法 —— 快速排序

快速排序

核心思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

盗来一张图:
这里写图片描述


算法优缺点
快速排序最“快”的地方在于左右两边能够快速同时递归排序下去,所以最优的情况是基准值刚好取在无序区的中间,这样能够最大效率地让两边排序,同时最大地减少递归划分的次数。此时的时间复杂度仅为O(NlogN)。
快速排序也有存在不足的情况,当每次划分基准值时,得到的基准值总是当前无序区域里最大或最小的那个元素,这种情况下基准值的一边为空,另一边则依然存在着很多元素(仅仅比排序前少了一个),此时时间复杂度为O(N*N)。

快速排序的速度快慢关键在于基准值的选取,它决定了划分次数以及比较次数,决定了快排的效率,因此,还有一些针对于基准值选取的优化方法,例如“三数据取中法”等,能够有效优化快速排序存在的不足之处。

空间复杂度:
其实这个空间复杂度不太好计算,因为有的人使用的是非就地排序,那样就不好计算了(因为有的人用到了辅助数组,所以这就要计算到你的元素个数了);我就分析下就地快速排序的空间复杂度吧;
首先就地快速排序使用的空间是O(1)的,也就是个常数级;而真正消耗空间的就是递归调用了,因为每次递归就要保持一些数据;
最优的情况下空间复杂度为:O(logn) ;每一次都平分数组的情况
最差的情况下空间复杂度为:O( n ) ;退化为冒泡排序的情况
稳定性:
因为在每次比较时会对基准前后的元素进行比较,可能导致相同大小的不同元素的相对位置发生改变。所以快速排序是一种不稳定的排序方法。


算法实现代码:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int []data  = new int[8];
        for(int i= 0;i<data.length ;i++){
            data[i] = sc.nextInt();
        }
        //快速排序
        quickSort(data ,0 ,data.length-1);

        for(int i = 0;i<data.length ;i++){
            System.out.print(data[i]+" ");
        }
    }
//快速排序的辅助方法
    public static int divide(int[] data, int start, int end){
        //每次都以最右边的元素作为基准值
        int base = data[end];
        //start一旦等于end,就说明左右两个指针合并到了同一位置,可以结束此轮循环。
        while(start < end){
            while(start < end && data[start] <= base)
                //从左边开始遍历,如果比基准值小,就继续向右走
                start++;
            //上面的while循环结束时,就说明当前的a[start]的值比基准值大,应与基准值进行交换
            if(start < end){
                //交换
                int temp = data[start];
                data[start] = data[end];
                data[end] = temp;
                //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值右边),因此右边也要同时向前移动一位
                end--;
            }
            while(start < end && data[end] >= base)
                //从右边开始遍历,如果比基准值大,就继续向左走
                end--;
            //上面的while循环结束时,就说明当前的a[end]的值比基准值小,应与基准值进行交换
            if(start < end){
                //交换
                int temp = data[start];
                data[start] = data[end];
                data[end] = temp;
                //交换后,此时的那个被调换的值也同时调到了正确的位置(基准值左边),因此左边也要同时向后移动一位
                start++;
            }
        }
        //这里返回start或者end皆可,此时的start和end都为基准值所在的位置
        return end;
    }

    //快速排序
    public static int[] quickSort(int[] data, int start, int end){
        if(start > end){
            //如果只有一个元素,就不用再排下去了
            return data;
        } else{
            //如果不止一个元素,继续划分两边递归排序下去
            int partition = divide(data, start, end);
            quickSort(data, start, partition-1);
            quickSort(data, partition+1, end);
        }
        return data;
    }
}

猜你喜欢

转载自blog.csdn.net/cqx13763055264/article/details/81699551