几种初级排序算法的总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/heheilije111/article/details/84693120

@TOC

几种初级排序算法的总结

排序就是将一组对象按照某种逻辑顺序重新排列的过程。

在本文中我们使用的操作:

  • 遍历数组
  • 比较两个对象(本文中所有代码示例中的less方法)
  • 交换两个对象 (本文中所有代码示例中的exch方法)

less 和 exch方法的源码:

private static boolean less(Comparable v, Comparable w) {
   return (v.compareTo(w) < 0);
}

private static void exch(Comparable[] a, int i, int j) {
   Comparable swap = a[i];
   a[i] = a[j];
   a[j] = swap;
} 

选择排序

选择排序的基本思路就是为每一个位置选择对的对象:

  1. 选择第一个位置;
  2. 从数组中未被选择的对象中选择最小(或最大)的对象放入当前选择的位置;
  3. 选择下一个位置,并重复2直到所有位置都有对象;

代码示例:

public static void sort(Comparable[] a) {
    int n = a.length;
    for (int i = 0; i < n; i++) {    //选择位置的循环
        int min = i;
        for (int j = i+1; j < n; j++) {     //选择剩余对象中最小元素
            if (less(a[j], a[min])) 
               min = j;
        }
        exch(a, i, min);    //交换位于选中位置上的元素和应该位于该位置的元素
    }
}

插入排序

插入排序的基本思路是将对象移动到已经有序的数组中适当的位置,类似打扑克牌时将新接的牌插入适当位置:

  1. 选中当前数组的第二个位置的对象;
  2. 比较当前选择的对象与位于它前面的对象,根据比较结果,如果两者现在相对位置是不对的,则交互它们,重复2.直到当前选择的对象前面没有元素或者,它和前面元素的相对位置是正确的;(一步一步往前挪)
  3. 选择下一个位置的元素,并重复2直到数组末尾;

示例代码:

public static void sort(Comparable[] a) {
    int n = a.length;
    for (int i = 1; i < n; i++) {     //选择需要挪动的对象
        for (int j = i; j > 0; j--) {    //一步一步往前挪
            if(less(a[j], a[j-1]))  //如果当前元素比前一个小,则交换位置
               exch(a, j, j-1);
            else
               break;      //已经挪到了对的位置,去挪下一个
        }
    }
}

希尔排序

希尔排序是一种基于插入排序的快速排序算法;对于大规模的乱序数组,插入排序会很慢,因为它只交换相邻的对象,元素要一点一点的往前挪;希尔排序的基本思路是分别对间隔h的元素组成的数组进行排序,使得原数组h有序,然后逐步减小h,如下图:
Alt text

  1. 选取一个h;
  2. 对间隔h的对象组成的数组进行插入排序;
  3. 减小h,重复2一直到h为1;

代码示例:

public static void sort(Comparable[] a) {
    int n = a.length;
    // 3x+1 increment sequence:  1, 4, 13, 40, 121, 364, 1093, ... 
    int h = 1;
    while (h < n/3) h = 3*h + 1;     //取一个大于等于数组长度三分之一的h
    while (h >= 1) {       
        // h-sort the array
        for (int i = h; i < n; i++) {    //使用插入排序对间隔h的对象组成的数组进行排序
            for (int j = i; j >= h && less(a[j], a[j-h]); j -= h) {
                exch(a, j, j-h);
            }
        }
        h /= 3;   //按3的倍数减小h
    }
}

性能与特性

  • 稳定性:选择排序的稳定性与具体实现有关,主要是判断大小的条件对对象相等的时候的处理,在我们的实现中它是不稳定的,因为它会交互两个相等的对象;插入排序是稳定的,因为挪动到相等元素时会停止;而基于插入排序的希尔排序却是不稳定的,因为分组的过程中会间接打乱相等对象的相对位置。
  • 空间:这三个算法都是直接在原数组上进行操作,并没有申请额外空间,且无递归,所以空间复杂度为O(1)。
  • 时间:选择排序的时间复杂度为O($ N^2 ) O ( N ) O ( );插入排序介于O(N) 到 O( N^2$) 之间,主要依赖于数组的有序程度,数组的有序程度越高,算法的效率越好;希尔排序大概是O(NlogN) ,同样和数组的有序程度相关,不过通过分组使得随机情况下算法的性能比插入排序更好。

**一点猜想:**从选择排序到希尔排序的性能变化,可能对应于算法对已排序对象的信息的利用程度的变化;比如一个数组中a、b、c是已经排好相对位置的元素,此时决定元素d的位置时,如果我们知道d>c,那么可以推理得出d>b以及d>a,选择排序对此类信息利用的相对较少,而插入排序相对利用的多些。

参考资料

猜你喜欢

转载自blog.csdn.net/heheilije111/article/details/84693120