快速排序(五)

 参考

算法 3:最常用的排序——快速排序

/**
 * Project Name:basic
 * File Name:QuickSortAlgorithm.java
 * Package Name:com.forwork.com.basic.sortAlgorithm
 * Date:2019年4月18日上午7:22:21
 * Copyright (c) 2019, 深圳金融电子结算中心 All Rights Reserved.
 *
*/

package com.forwork.com.basic.sortAlgorithm;

import java.util.Arrays;

/**
 * ClassName:QuickSortAlgorithm <br/>
 * Function: 因此快速排序的最差时间复杂度和冒泡排序是一样的都是 O(N2),它的平均时间复杂度为 O(NlogN)。
 * 其实快速排序是基于一种叫做“二分”的思想。<br/>
 * Date:     2019年4月18日 上午7:22:21 <br/>
 * @author   Administrator
 * @version   1.0
 * @since    JDK 1.7
 * @see      
 */
/*     快速排序的思想:(1)首先判断左右哨兵的关系(break),然后选取基准数temp,然后从左向右找到小于temp的元素停下来,接着从右向左找到大于temp的元素停下来
(2)如果左右哨兵不相等,就交换左右两个哨兵的元素
(3)重复(1)(2),直到左右哨兵相等,将哨兵i元素和temp互换
(4)再次重复递归*/
public class QuickSortAlgorithm {

    public static void quickSort(int[] array, int left, int right) {
        int i, j, t, temp;
        //相当重要,必不可少,退出递归的条件
        if (left > right)
            return;
        System.out.println("base:" + array[left] + " " + Arrays.toString(array));
        i = left;
        j = right;
        temp = array[left];

        while (i != j) {

            //顺序很重要,先从右往左找,找到小于基准数temp的元素停下来
            while (i < j && array[j] >= temp)
                j--;
            //再从左往右找,找到大于基准数temp的数停下来
            while (i < j && array[i] <= temp)
                i++;

            //交换两个数在数组中的位置
            if (i < j) { //当哨兵i和哨兵j没有相遇时
                t = array[j];
                array[j] = array[i];
                array[i] = t;
            }
        } //end while

        //最终将基准数归位,此时i=j
        array[left] = array[i];
        array[i] = temp;

        quickSort(array, left, i - 1); //继续处理左边的,这里是一个递归的过程
        quickSort(array, i + 1, right); //继续处理右边的,这里是一个递归的过程

    }

    public static void main(String[] args) {
        int[] array = { 4, 3, 5, 8, 7, 6, 1, 2, 5 };
        int left = 0;
        int right = array.length - 1;
        quickSort(array, left, right);
        System.out.println("end:" + Arrays.toString(array));
    }

}

运行结果:

base:4 [4, 3, 5, 8, 7, 6, 1, 2, 5]
base:1 [1, 3, 2, 4, 7, 6, 8, 5, 5]
base:3 [1, 3, 2, 4, 7, 6, 8, 5, 5]
base:2 [1, 2, 3, 4, 7, 6, 8, 5, 5]
base:7 [1, 2, 3, 4, 7, 6, 8, 5, 5]
base:5 [1, 2, 3, 4, 5, 6, 5, 7, 8]
base:6 [1, 2, 3, 4, 5, 6, 5, 7, 8]
base:5 [1, 2, 3, 4, 5, 5, 6, 7, 8]
base:8 [1, 2, 3, 4, 5, 5, 6, 7, 8]
end:[1, 2, 3, 4, 5, 5, 6, 7, 8]
View Code

快速排序之所比较快,因为相比冒泡排序,每次交换是跳跃式的。每次排序的时候设置一个基准点,将小于等于基准点的数全部放到基准点的左边,将大于等于基准点的数全部放到基准点的右边。这样在每次交换的时候就不会像冒泡排序一样每次只能在相邻的数之间进行交换,交换的距离就大的多了。因此总的比较和交换次数就少了,速度自然就提高了。当然在最坏的情况下,仍可能是相邻的两个数进行了交换。因此快速排序的最差时间复杂度和冒泡排序是一样的都是 O(N2),它的平均时间复杂度为 O(NlogN)。其实快速排序是基于一种叫做“二分”的思想。

快速排序特点总结:

(1)最坏时间复杂度:最坏情况是每次区间划分的结果都是基准关键字的左边(或者右边)序列为空,而另一边区间中的记录项仅比排序前少一项,即选择的基准关键字是带排序的所有记录中最小或者最大的。最坏情况下时间复杂度是O(n^2).

(2)最好时间复杂度:选择的基准关键字为待排序的记录的中间值。时间复杂度为O(nlogn

(3)平均时间复杂度:平均时间复杂度为O(nlogn)。在所有平均时间复杂度为O(nlogn)的算法中,快速排序的平均性能是最好的。

(4)空间复杂度:快速排序的实现过程中需要一个栈空间来是先递归。快排的平均空间复杂度为O(logn)

(5)基准关键字的选取。基准关键字的选取是决定快速排序算法性能的关键。常用的基准关键字的选取方式如下:

三者取中:在当前序列中,将其首、尾和中间位置上的记录进行比较,选择三者的中值作为基准关键字,在划分开始前交换序列中的第一个记录与基准关键字的位置。

取随机数:取left(左边)和right(右边)之间的一个随机数m(left<=m<=right),用n[m]作为基准关键字。这种方式使得n[left]和n[right]之间的记录时随机分布的,采用此方法得到的快速排序一般称为随机的快速排序。


快速排序与归并排序的区别于联系:

联系:快速排序和归并排序的原理都是基于“分而治之”思想,即首先把待排序的元素分成两组,然后分别对这两组排序,最后把两组结果合并起来。

区别:进行分组的策略不同,后面的合并策略也不同。

归并排序的分组策略是假设待排序的元素存放在数组中,那么其把数组前面一半元素作为一组,后面一半作为另外一组。

而快速排序则是根据元素的值来分组,即大于某个值的元素放在一组,而小于的放在另外一组,该值称为基准。

所以,对整个排序过程而言,基准值的挑选就非常重要,如果选择不合适,太大或太小,那么所有元素都分在一组了。总的来说,快速排序和归并排序,如果分组策略越简单,则后面的合并策略就越复杂,因为快速排序在分组时,已经根据元素大小来分组了,而合并时,只需把两个分组合并起来就行了,归并排序则需要对两个有序的数组根据大小合并

得出结论  

选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,而冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法

原文地址:https://www.cnblogs.com/lixuwu/p/5676172.html