基础排序算法学习

在一次面试之后,觉得自己的算法能力还是偏弱,虽然常用的排序,查找算法都比较熟悉,不过面试的时候问了一个算法题,思路跑偏了没答上来,题的内容是找出一个字符串中有多少回文子串,还是比较有难度的。接下来的一段时间,想加强一下自己的算法能力,弥补下自己的不足,也希望这一段时间的算法学习会比较有收获,最后的目标是算法的灵活使用,能通过算法解决实际问题最好。先从排序算法开始学习
一.选择排序
选择排序在排序算法中可以算是最简单的一种排序方法了,思路是:首先,找到数组中最小的元素,将它和数组中第一个元素进行交换。其次,在剩下的数组中找出最小的元素,将它和数组中第二个元素交换。如此反复,知道将数组完全排序,这种方法叫做选择排序,因为它在不断的选择数组中最小的元素。
  /**
     * 选择排序
     * 选择排序的思想是每次找到当前数组中最小的索引
     * @param array
     */
    public static void chooseSort(int [] array){
        int length = array.length;
        for(int i = 0;i < length;i++){
            int min = i;
            for(int j = i+1;j < length;j++){
                if(array[j] < array[min]){
                    min = j;//找到最小的元素下标
                }
            }
            if(min != i){
                swapArray(array,min,i);//交换数组中指定两个位置的元素
            }
        }
    }
选择排序的时间复杂度是O(N^2),平均空间复杂度是O(1),还有一个稳定性的概念: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序后,这些记录的相对次序保持不变,即在原序列中,ri=rj,且ri在rj之前,而在排序后的序列中,ri仍然在rj之前,则称这种排序算法是稳定的。这里选择排序是不稳定的。
二.插入排序
通常人们整理桥牌的方法是一张一张的来,将每一张牌插入到其他已经有序的牌中的适当位置。在计算机的实现中,为了给要插入的元素腾出空间,我们需要将其余所有元素在插入之前都向右移动一位。这种算法叫插入排序。
与选择元素一样,当前索引左边的元素都是有序的,但它们的最终位置还不确定,为了给更小的元素腾出空间,它们可能会被移动。但是当索引的元素到达数组的右端时,数组排序就完成了。
和选择排序不同的是,插入排序所需的时间取决于输入中元素的初始顺序。如果数组元素已经比较有序了,那么插入排序性能就会很高。值得注意的是,Java里的Arrays.sort方法实现源码中,当数组元素比较少的时候使用的就是插入排序算法排序(事实上是在插入排序的基础上做了一些优化,每次同时完成两个元素的插入排序,被称之为双插入排序算法)。
  /**
     * 插入排序算法
     * @param array
     */
    public static void insertSort(int []array){
        int length = array.length;
        for(int i = 1;i < length;i++){
            for(int j = i;j > 0;j--){
                if(array[j] < array[j-1]){
                    swapArray(array,j,j-1);
                }
            }
        }
    }
上面的插入排序代码其实和我最开始预想的不太一样,这段代码看上去更像冒泡排序,我最开始预想的插入排序是遍历数组中的元素,找到当前元素应该在已排好序元素中的位置,将当前元素插入到这个位置中。而大多数插入排序代码都是上面的写法,看了下Arrays.sort里的方法也基本和上面的代码一致。
插入排序的时间复杂度是O(n^2)。当最好的情况,也就是要排序的表本身就是有序的,此时只有数据比较,没有数据移动,时间复杂度为O(n)。
当最坏的情况,即待排序的表是逆序的情况,此时需要比较次数为:2+3+…+n=(n+2)(n-1)/2 次,而记录移动的最大值也达到了 (n+4)(n-1)/2 次.
如果排序记录是随机的,那么根据概率相同的原则,平均比较和移动次数约为N^2/4,因此,得出直接插入排序发的时间复杂度为O(N^2)。从这里可以看出,同样的是时间复杂度O(N^2 ,直接插入排序法比冒泡和简单选择排序的性能要好一些。
总的来说,插入排序对于部分有序的数组十分高效,也很适合小规模的数组,这也是Arrays.sort在元素小于指定值时,使用插入排序算法的原因。经过测试,选择排序的排序时间大约是插入排序的1.7倍。
不同场景下选择排序和插入排序的性能比较
1.元素都相同时,选择排序和插入排序哪个快?
当数组中的所有元素都相同时,插入排序算法更快。当元素都相同时,插入排序比较次数为N-1,交换次数0;选择排序比较次数为N( N-1)/2,交换次数为0。
2.对于逆序数组,选择排序和插入排序哪个快?
数组为逆序数组时,选择排序更快。数组逆序时,插入排序由于逆序对有N(N-1)/2对,所以交换次数是N(N-1)/2,比较次数大于等于交换次数,小于等于交换次数+N-1。对于选择排序,不管输入是怎样的,比较次数都是N(N-1)/2,交换次数为N-1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值