排序算法分析 - java版本

1. 希尔排序

希尔(Shell)排序又称为缩小增量排序,它是一种插入排序。它是直接插入排序算法的一种威力加强版。

主要是为了解决插入排序中,在集合前面有序元素过多时导致的重复无用循环的问题。


由于属于插入排序的变种,故基本原理也是插入排序的原理,将整个集合分为有序以及无无序两个部分,然后从无序部分中不断取出元素放入有序集合部分。

但是希尔排序引入了一个叫步长(gap)的概念,本质是将集合分组。

希尔排序是不稳定的,即两个相同的元素相对位置,在排序后可能会发生变化。

如图:
希尔排序示意图
步骤分析

  1. 将长度为10的集合分为 10/2 = 5 组,这五组各自有两个元素。分别对每个组内的这两个元素进行插入排序。

    在这一步之后 ,若集合本身前面是有序的,只是后面有些无序序列时,此时的无序序列也已经会被前移到前半部分了

  2. 继续缩小步长(缩小一倍),再次分批进行插入排序。直至步长为1,再次进行最后一次插入排序,可以有效降低插入排序的无效次数

JAVA代码实现:

/**
     * 希尔排序(插入排序变种)
     * <p>
     * 为了改善插入排序的一些弊端。比如原数组本来在前面就有很多的有序元素,插入排序前面的很多遍历就都成为了徒劳,对程序的浪费
     * 希尔排序会将集合先进行分组,先按每组来排序,然后减小分组,继续进行插入排序。直至分组数小于0
     * [4, 2, 17, 3, 85, 0, 31, 2, 7, 61, 43, 87, 31, 39, 38, 42, 72, 24, 20, 55]
     * 20个元素,首先分10组,其中,下标位0,10是一组,1,11 是一组,2,12是一组,。。。
     * 第二次,分5组,下表0,5,10,15为一组,1,6,11,16是一组。。。。
     * 第三次,分2组,下表0,2,4,6,8,10,12,14,16,18为一组,1,3,5,7,9,11,13,15,17,19 为一组
     * 最后分组数为1,进行整体插入排序
     *
     * @param arr
     */
    public static void shellOrder(int[] arr) {
        int buc = arr.length / 2;
        while (buc > 0) {
            for (int x = buc; x < arr.length; x++) {
                int cur = arr[x];
                int y = x - buc;
                for (; y >= 0; y -= buc) {
                    if (arr[y] > cur) {
                        int temp = arr[y];
                        arr[y+buc] = temp;
                        arr[y] = cur;

                    }else {
                        break;
                    }
                }
                arr[y+buc] = cur;
            }
            buc = buc / 2;
        }
    }

下面是插入排序的算法。可以和希尔排序比较一下,就会发现其实本质就是多了个分组的步骤

    /**
     * 插入排序
     * <p>
     * 对欲排序的元素,以插入的方式寻找其合适的位置。
     * 个人理解:插入排序其实就是选择排序的变种。选择排序是先选择合适的元素,放在当前位置。
     * 而插入排序,则是直接找当前位置的元素,插入到顺序表合适的位置
     *
     * @param arr
     */
    public static void insertOrder(int[] arr) {
        //省略判断数组有效性步骤

        for (int x = 1; x < arr.length; x++) {
            int cur = arr[x];
            int y = x-1;
            for (; y >=0; y--) {
                if (arr[y] > cur) {
                    arr[y+1] = arr[y];
                }else {
                    break;
                }
            }
            arr[y+1]=cur;
        }
    }

2. 归并排序

归并排序讲究的是一个分而治之的策略。面对一个无序杂乱的集合,归并排序的做法是不断地将其分割成为一个个零散的小集合,再将每个小集合依次排序组合。


图示:
在这里插入图片描述
可以看出来,归并算法大致分为分,与治两个大步骤。
:就是将集合不断两两细分,直到分割成不可分割的最小元素

:将分割的元素,按照顺序再组合成一个集合
在这里插入图片描述

在这里插入图片描述

由此可以知道,归并排序的分和治是分开的。并且归并排序是稳定的相同大小的元素,在排序前后的相对顺序不会发生改变。

    /**
     * 归并排序
     * @param arr
     */
    public void mergeOrder(int[] arr){
        //使用递归进行分
        radixOrder(arr,0,arr.length-1,new int[arr.length]);
    }

    private static void radixOrder(int[] arr,int left,int right,int []temp){
        if (left<right){
            int mid = (left+right)/2;
            radixOrder(arr,left,mid,temp);
            radixOrder(arr,mid+1,right,temp);
            merge(arr,left,right,mid,temp);
        }
    }

    private static void merge(int[] arr,int left,int right,int mid,int[] temp){
        int lstart = left;
        int rstart = mid+1;

        int t =0;

        while (lstart<=mid&&rstart<=right){
            if (arr[lstart]<arr[rstart]){
                temp[t++] = arr[lstart++];
            }else {
                temp[t++] = arr[rstart++];
            }
        }

        while (lstart<=mid){
            temp[t++] = arr[lstart++];
        }

        while (rstart<=right){
            temp[t++] = arr[rstart++];
        }

        t=0;
        while (left<=right){
            arr[left++] = temp[t++];
        }
    }
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值