Skip to content

Latest commit

 

History

History
75 lines (59 loc) · 3.52 KB

sort.md

File metadata and controls

75 lines (59 loc) · 3.52 KB

定义

排序的定义: 对一序列对象根据某个关键字进行排序。

术语说明:

  • 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面;
  • 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面;
  • 内排序:所有排序操作都在内存中完成;
  • 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行;
  • 时间复杂度: 一个算法执行所耗费的时间。
  • 空间复杂度:运行完一个程序所需内存的大小。

分类

排序算法分类 排序从大的方便可以分为内部排序和外部排序。我们通常所说的排序算法往往指的是内部排序算法,即数据记录在内存中进行排序。

排序算法大体可分为两种:

  • 比较排序: 时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。
  • 非比较排序,时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等。 下表给出了常见比较排序算法的性能:

排序算法性能

通常有一点我们很容易忽略的是排序算法的稳定性。

排序算法稳定性的简单形式化定义为:如果Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。通俗地讲就是保证排序前后两个相等的数的相对顺序不变。

对于不稳定的排序算法,只要举出一个实例,即可说明它的不稳定性;而对于稳定的排序算法,必须对算法进行分析从而得到稳定的特性。需要注意的是,排序算法是否为稳定的是由具体算法决定的,不稳定的算法在某种条件下可以变为稳定的算法,而稳定的算法在某种条件下也可以变为不稳定的算法。

例如,对于冒泡排序,原本是稳定的排序算法,如果将记录交换的条件改成A[i] >= A[i + 1],则两个相等的记录就会交换位置,从而变成不稳定的排序算法。

其次,说一下排序算法稳定性的好处。排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,前一个键排序的结果可以为后一个键排序所用。基数排序就是这样,先按低位排序,逐次按高位排序,低位排序后元素的顺序在高位也相同时是不会改变的。

本章的所有排序实现类都实现了以下接口:

public interface ISort {
    //核心接口
    int[] sort(int []data);
    //交换
    default void swap(int[] data, int i, int j){
        data[i] = data[i] ^ data[j];
        data[j] = data[i] ^ data[j];
        data[i] = data[i] ^ data[j];
    }
    // 打印数组
    default void print(int [] data){
        System.out.println("");
        for(int i = 0; i < 50; i++){
            System.out.print(data[i]);
            System.out.print(", ");
        }
        System.out.println("");
    }
}

测试代码如下:

public class Main {
    public static void main(String[] args) {
        // 初始化一个排序类
        ISort sort = new MergeSort();
        //初始化数组
        int[] data = {42, 41, 14, 14, 27, 24, 0, 3, 25, 2, 42, 11, 20, 9, 41, 37, 9, 1, 10, 16, 28, 19, 12, 39, 11, 19, 6, 26, 44, 4, 21, 10, 40, 27, 43, 35, 41, 42, 17, 17, 9, 32, 35, 0, 30, 40, 16, 32, 32, 48};
        //排序
        sort.sort(data);
        //打印排序结果
        sort.print(data);
    }
}