排序算法

一、稳定性


 

何为稳定:假设A==B 排序前A再B前面,排序后A依然在B前面,这就是稳定的排序算法

                 如冒泡排序 插入排序 归并排序可以是稳定的。快速排序 选择排序是不稳定的。

 

稳定性跟具体算法实现有关:我们说冒泡排序是稳定的 如果我们的冒泡算法判断A>=B 则交换A和B,这种写法那就不稳定了

                                               因为A==B的情况下 最终排序后A在B之后了。

 

稳定性好处:多重排序某些场景可以避免 不必要的二次排序,我们就拿经常举的例子来看

                     加入全年级学生已经按学号进行了排序,再按班级排序后,需要满足同一班级的学生学号也是排序的

                     这样稳定的排序算法 按班级排序后,就已经满足要求了;非稳定的排序那必须再进行学号的排序。

 

二、10大基本排序算法


 

 

 

1、冒泡排序

相连元素两两比较,每轮把最大的往后移,

一轮之后最大的数在最后位置 

二轮之后第二大的数在倒数第2的位置

... 

 

 

2、选择排序

每次选择1个位置存在最大的数

一轮从第2个数开始每个跟第1个数比较,比其大就替换,第一个位置的数最大

二轮从第3个数开始每个跟第2个数比较,比其大就替换,第二个位置的数次大

...

 

 

 

3、快速排序

每次拿出一个数作为基数,一帮是开头的数,后面的数比其小就放入其左边,比其大就放入其右边,左右两个部分再这样处理

二分的思想。

 

 

 

代码如下:

public class QuickSort {
    public static void quickSort(int[] array) {
        if (array == null || array.length <= 1) {
            return;
        }
        quickSort(array,0,array.length - 1);
    }
    /**
     * 快排
     * @param array 数组
     * @param start 起点
     * @param end 终点
     * @return 排序后的array
     */
    public static void quickSort(int[] array, int start, int end) {
        if (array.length < 1 || start < 0 || end >= array.length || start > end) {
            return;
        }

        if (array.length == 1) {
            return;
        }

        // 以start为基准(pivot) 把小于start放入左边 大于start的放在右边
        int pivotIndex = sortPivot(array, start, end);
        quickSort(array, start, pivotIndex - 1);
        quickSort(array, pivotIndex + 1, end);
    }

    /**
     *  一轮快排
     *  以start为基准(pivot) 把小于start放入左边 大于start的放在右边
     * @param array
     * @param start
     * @param end
     * @return 基准数最终放入的位置
     */
    public static int sortPivot(int[] array, int start, int end) {
        // 一般以start为基准(任意都可以)
        int pivot = start;
        int indexI = start;
        int indexJ = end;
        /*
         从两端不断的向前走 先处理从后往前,直到遇到某个indexJ小于array[pivot]
         再从start往后 直到遇到一个indexI array[indexI] >= array[pivot]
         交换indexI indexJ ,不断循环直到indexI==indexJ ,交换pivot与indexI
          */
        for (; indexJ > indexI; --indexJ)
            if (array[indexJ] < array[pivot]) {
                for (; indexI<=end;++indexI) {
                    if (array[indexI] >= array[pivot]) {
                        swap(array, indexI,indexJ);
                        break;
                    }
                }
                continue;
            }
        swap(array, pivot,indexI);
            return indexI;
    }

    /**
     * 交换数组内两个元素     * @param array     * @param i     * @param j
     */
    public static void swap(int[] array, int i, int j) {
        if (i == j) {
            return;
        }
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public static void main(String[] args) {
        int[] array = {1,2,6,8,3,9,4};
        quickSort(array);
        System.out.println("sorted array = " + Arrays.toString(array));
    }

}
View Code

 

4、插入排序

每次拿当前元素和前面元素比较,从后往前依次比较,遇到比其小的,则插入到其后面

 

第一轮 第2个数与第1个数比较,A2<A1,则交换

第二轮 第3个数与前面2个数比较,先比较A3 A2, 若A3<A2  , 则把A2往后移 ,继续与A1比较,若A1>A3,则A1也往后移一位

...

 

5、希尔排序

最早突破O(n^2)的一批算法,是插入排序的改进版,

算法思想:把数组不断分成多个组, 每组使用插入排序 (缩小增量序列)

一般的是以数组长度的一般作为间隔 ,相同间隔的就是一组 (希尔序列)

如数组长度为n ,一开始间隔为n/2  则A[0]  A[n/2]  A[0 + 2(n/2)] 为一组,这组按插入排序方法进行排序

然后不断间隔长度,间隔为(n/2)/2 再把相同组的元素排序。

 

如下 相同颜色的就是一组

 

6、归并排序

二分思想 分成2半 ,每半分别排序后,再把两个排序好的子序列从头依次比较,进行归并排序,这个过程不断递归

 

求逆序对的算法 可以基于归并排序的思想。

 

7、堆排序

利用大顶堆(小顶堆)的特性(即二叉树的根节点总是大于(或小于)其子节点,子树也满足)来进行排序

首先使用原始数组构建大顶堆,从堆中取根节点,就是最大的

余下的数重新构建大顶推 ,从堆中取根节点,就是次大的,依次这个过程。

 

构建大致过程:

a、拿树的最后的元素,即右下角的元素,移至堆顶

b.  堆顶元素跟左右子节点比较,把大的元素交换至堆顶,子树递归比较

 

8、计数排序

以空间换时间, 取数组中最大值,定义一个额外的数组,新数组大小就是原始数组中最大的值

一轮遍历,把原始数组对应元素放入新数组对应位置,对应位置计数加一A[i]++, 最后再从新数组中一一取出即可

限制:数组元素有明确范围 不能太大

 

9、桶排序

 基于计数排序思想, 每个桶定义一段范围,把对应元素放入对应桶内,再对桶内的元素使用任一排序算法排序

 

10、基数排序

是按基数进行排序,如数字有0,1,2,...,9  共10个基数,字母有a,b,c,...,z共26个基数

从个位开始比较,把元素放入各个基数对应的队列中,再取出,就满足按个位比较是排序好的

再比较十位,以此类推,优先级不断增加

(这利用了基数排序的文档性,低优先级的排序,不会随着高优先级的排序而打乱)

 

三、复杂度对比


 

时间最快的排序算法:计数排序 

稳定的排序算法:冒泡、插入、归并、计数、桶、基数

 

四、JDK Arrays.sort排序实现


 List的sort最终也会调用Arrays.sort方法 

JDK中数组的排序不是唯一的,插入排序、归并和快排都可能使用

 

 

参考: https://www.cnblogs.com/onepixel/articles/7674659.html

           https://www.cnblogs.com/baichunyu/p/11935995.html

posted @ 2020-03-18 23:34  蓝天随笔  阅读(190)  评论(0编辑  收藏  举报