常用排序算法总结----快速排序(java实现)

快速排序使用分治策略来把一个序列(list)分为两个子序列(sub-lists)。步骤为:

①. 从数列中挑出一个元素,称为”基准”(pivot)。
②. 重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
③. 递归地(recursively)把小于基准值元素的子数列和大于基准值元素的子数列排序。

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

实现思路:

快速排序的算法思想其实比较简单,先找出一个数作为基准数(通常取数组最小下标或者最大下标位置的数字)。定义两个变量作为“哨兵”,然后分别从后向前,从前向后两个方向去“探测”:

  1. 从后向前:寻找比基准数小的数据,如果找到,停下来
  2. 从前向后:寻找比基准数大的数据,如果找到,停下来
  3. 如果两个方向的“探测”都找到了符合要求的数据,则交换数据,继续顺着方向寻找
  4. 直到两个哨兵碰到一起,此时把相遇位置上的数据和基准数(即数组的中间位)交换数据
  5. 此时,基准数左侧的数都小于等于基准数,右侧的数都大于等于基准数
  6. 同样的方法去“探测”基准数左侧和右侧的数据(使用递归) 

                         

代码如下:

    public static void QuickSort(int[] arr){
        // 定义两个哨兵  分别为 数组的最小下边  和数组的最大下标
        sort(arr,0,arr.length-1);

    }

    public static void sort(int[] arr , int left ,int right){
        if(left<right){
            // 通过基准数字将数组左右分为两个子数组
            // 数组中小于基准的数放在左边  大于基准的数字调换到右边
            // 递归子数组
            int pvtion = partion(arr,left,right);
            sort(arr,left,pvtion-1);
            sort(arr,pvtion+1 , right);
        }
    }
    public static int partion(int[] arr , int left ,int right){
        int pvtion = arr[left]; //依数组中最左边的数字作为基准

        while (left < right){  // 左边数组下标 小于右边数组下标

            while (arr[right] >pvtion && left<right)
                right--; //当右边的哨兵位置上的数字大于基准数字  哨兵左移  直达哨兵到达位于从右边开始第一个小于基准的数字

            if(left< right){
                // 把最右边第一个小于基准的数字换到最左边位置
                // 因为我们以最左边的哨兵为基准 ,所以直接赋值到该哨兵位置
                arr[left++] = arr[right]; //类似于 arr[left] = arr[right];left++;
            }

            while(arr[left] <= pvtion && left<right)
                left++;//当左边的哨兵位置上的数字小于基准数字  哨兵右移  直达哨兵到达位于从左边开始第一个大于基准的数字
            if(left <right){
                arr[right--] = arr[left]; //把该大于基准的数字的换到右边
            }
        }
        arr[left] = pvtion;  //把基准数字放在中间位置
        return left; // 返回中间位置的下标
    }

以下是快速排序算法复杂度:

最坏时间复杂度 \Theta (n^{2})
最优时间复杂度 \Theta (n\log n)
平均时间复杂度 \Theta (n\log n)
最坏空间复杂度 根据实现的方式不同而不同

 虽然它运行最糟糕时将达到O(n²)的时间复杂度, 但通常平均来看, 它的时间复杂为O(nlogn), 快速排序似乎更偏爱乱序的数列, 越是乱序的数列, 它相比其他排序而言, 相对效率更高.

Tips: 同选择排序相似, 快速排序每次交换的元素都有可能不是相邻的, 因此它有可能打破原来值为相同的元素之间的顺序. 因此, 快速排序并不稳定.

  

猜你喜欢

转载自blog.csdn.net/lele52080/article/details/81485359