常见排序算法JAVA版代码时间复杂度空间复杂度稳定性(标准命名及标准写法)

0、概述

0.1、排序的稳定性

当待排序列关键字各不相同时,排序结果唯一,否则结果不唯一。在待排序列文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,则该方法是稳定的。

0.2、排序的分类

内部排序和外部排序,此处只讨论内部排序

内部排序分为:

  • 插入类:
  • 交换类:
  • 选择类:
  • 归并类:
  • 分配类:
0.3、排序的性能评价

执行时间与所需辅助空间和算法本身的复杂程度

注意:下面的算法中,待排序数组的零地址不存放数组元素,用来做“监视哨”或者空闲不用

0.4、总体比较

img

1、插入排序

1.1、直接插入排序
    public static void insertSort(int[] arr){

        for(int i = 2;i<arr.length;i++){
            if(arr[i]<arr[i-1]){
                arr[0] = arr[i];
                int j = i-1;
                for (; arr[0]<arr[j] ;j--){
                    arr[j+1] = arr[j];
                }
                arr[j+1] = arr[0];
            }
        }
    }

样例:[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

排序结果:[1, 1, 2, 3, 4, 5, 6, 7, 8, 9]

时间复杂度:正序时O(n) 逆序时O(n[^2])

当待排元素已经为正序时,或者接近正序时所比较的次数和移动次数比较少。对于小规模来说,插入排序是一个快速的排序法。

空间复杂度:O(1) 只需要一个监视哨arr[0]

稳定性:稳定

1.2、希尔排序
    private static void shelltSort(int[] arr,int dk) {

        int i = dk+1;
        for(;i<arr.length;i++){

            if(arr[i]<arr[i-dk]){
                arr[0] = arr[i];
                int j = i-dk;
                for(;j>=0&&(arr[0]<arr[j]);j=j-dk){
                    arr[j+dk] = arr[j];
                }
                arr[j+dk] = arr[0];
            }
        }

    }

样例:[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

排序结果:[8, 1, 2, 3, 4, 5, 6, 7, 8, 9]

时间复杂度:dk的取值为{2[k]-1,2[k-1]-1,…,7,3,1}时,时间复杂度 O(n[^3/2])

如果dk每次除以2递减那么时间复杂度依旧是O(n[^2])

空间复杂度:O(1) 只需一个辅助空间

稳定性:不稳定

2、交换排序

2.1、冒泡排序
    private static void bubbleSort(int[] arr) {

        for(int i = 1;i<=arr.length-1;i++){
            // 设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成。
            boolean flag = true;
            for(int j = 1;j<arr.length-i;j++){

                if(arr[j]>arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag  =false;
                }
                
            }
            if(flag) break;
        }
    }

样例:[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

排序结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

时间复杂度:正序时为O(n) 逆序时O(n[^2])

空间复杂度:O(1) 只需要一个辅助空间交换元素

稳定性:稳定

2.2、快速排序
    private static void quickSort(int[] arr,int low,int high) {
        if(low<high){
            int pos = quickPass(arr,low,high);
            quickSort(arr,low,pos-1);
            quickSort(arr,pos+1,high);
        }

    }

    //一趟快速排序
    private static int quickPass(int[] arr,int low,int high){
        arr[0] = arr[low];
        while (low<high){
            while (low<high&&arr[high]>arr[0])  high--;
            arr[low] = arr[high];
            while (low<high&&arr[low]<arr[0]) low++;
            arr[high] = arr[low];
        }
        arr[low] = arr[0];
        return low;
    }

样例:[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

排序结果:[4, 1, 2, 3, 4, 5, 6, 7, 8, 9]

时间复杂度:快速排序的最坏运行情况(正序)是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。

空间复杂度:总共需要分割logn次所以空间复杂度为logn

稳定性:不稳定

3、选择排序

3.1、简单选择排序
    private static void selectSort(int[] arr) {
        int i = 1;
        for(;i<=arr.length-1;i++){
            int k = i;
            for (int j = i+1;j<=arr.length-1;j++ ){
                if(arr[j]<arr[k]){
                    k = j;
                }
            }
            if(k != i){
               int temp = arr[i];
               arr[i] = arr[k];
               arr[k] = temp;
            }
        }
    }

样例:[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

排序结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

时间复杂度:O(n[^2])

空间复杂度:O(1)

稳定性:不稳定

3.2、堆排序

注意:堆排序的数组第一个位置我没有空闲,而是放了关键字

所以左孩子是i * 2+1,右孩子是i * 2+2,最后一个非叶子结点是n/2-1

	//堆排序
    private static void heapSort(int[] arr) {

        creatHeap(arr);
        for(int i = arr.length-1;i>=1;i--){
            int temp = arr[0];
            arr[0] = arr[i];
            arr[i] = temp;
            heapAdjust(arr,0,i-1);
        }

    }

    //创建堆
    private static void creatHeap(int[] arr) {

        int len = arr.length;
        //最后一个非叶子节点
        for(int i = len/2-1;i>=0;i--){
            heapAdjust(arr,i,arr.length-1);
        }

    }

    /**
     *  调整堆
     * @param arr
     * @param i 堆得根节点的下标
     * @param length 堆的最后节点的下标
     */
    private static void heapAdjust(int[] arr, int i, int length) {
        int temp = arr[i];
        for (int j = 2*i+1;j<=length;j=j*2+1){
            if(j<length && arr[j] < arr[j+1]){
                j++;
            }
            if(temp>=arr[j]) break;
            arr[i] = arr[j];
            i = j;
        }
        arr[i] = temp;
    }

样例:[0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

排序结果:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

时间复杂度:O(logn)

空间复杂度:O(1)

稳定性:不稳定

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值