Sorting algorithm summary (a)

I. Introduction

This blog belongs to the review of the sorting algorithm is mainly based on the "algorithm" a book. Blog text focused mainly implementation of the algorithm, such as for helper methods less(), exch()and isSorted()so on venue and sorting algorithm template code view to achieve.

Note : All images in this article are auxiliary picture "algorithm," a book, code implementation also comes from the book.

  This article is refining its point, you want to study in detail these algorithms watch on their own books.

Second, the text

This blog will review three sorting algorithm is:

  • Selection Sort
  • Insertion Sort
  • Shell sort

1. Select Sort

Select sort is the most simple sorting algorithm, based on their characteristics and complexity, almost no use to select the sort to solve practical problems of the sort, but it's thought for our entry-sorting algorithm is a certain guiding significance.

1.1 ideas

First, find the smallest element in the array, and secondly, it will be the first element of the array and exchange (if the first element is the smallest element and then it own exchange). Again, the rest of the elements found in the smallest element, it will be exchanged with the second element of the array ... so back and forth, until the entire array is sorted.

1.2 code implementation

Select sorted Java code implementation is as follows:

public class Selection {

	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;
	            }
	        }
	        // 将a[i]和a[min]进行交换
	        exch(a, min, i);
	    }
	    assert isSorted(a);
	}
	
	// less()、exch()和isSorted()方法见本文开头
}

1.3 algorithm complexity

For an array of length N, selection sort takes about   N 2 / 2 \ N{^2}/2 comparisons and   N \ N times the exchange.

Proof . Our array [SORTEXAMPLE] sort prove this complexity. We use a   N N \ N✖N tables indicate the sort of track, in which each character represents a non-gray compared. About half of the table character is not gray. Each element on the diagonal line and corresponds to the first exchange. As shown in the following table.
Here Insert Picture Description
I min and left corresponding to the following numerals denote array subscript and black elements to the minimum switching element in the corresponding array subscripts. Wherein the element represents a gray element has been scheduled good; black element representation comparing element in the current cycle; red elements and represents the smallest element is about a [i] exchange.
Can be clearly seen from the figure, the array of length N, the number of comparisons required about   N 2 / 2 \ N{^2}/2 times the number needed to exchange about   N \ N times.

1.4 Features

Select the sort There are two very distinct characteristics:

  • Running time and independent of the input . Select the sort order to find the smallest element array and scan it again does not provide any information for the next pass of the scan, which is a big disadvantage, because even an already ordered array or an array of all elements of the same, using the selection sort array and the time required to sort a random element is used as long as the time.
  • Data movement is the least . Each exchange will change the sorting selecting two values of the array elements, thus selected for sorting the   N \ N times switching, i.e. switching the size and number of linear arrays. Other sorting algorithms do not have this feature.

2. Insertion Sort

Insertion sort of thinking is somewhat similar to the way people organize when the bridge, about to each card inserted into the appropriate position other cards have been ordered in.

2.1 ideas

There is an array A [], assuming all the elements a [i] are ordered left, but they are not determining final position, in order to make room for smaller elements, they may be moved. However, when the index reaches the right end of the array, sort the array is complete.

2.2 代码实现

插入排序的 Java代码实现如下所示:

public class InsertionX {

	public static void sort(Comparable[] a){
	    int n = a.length;
	    for (int i = 1; i < n ; i++){
	        for (int j = i; j > 0 && less(a[j], a[j-1]); j--){
	            exch(a, j, j-1);
	        }
	    }
	    assert isSorted(a);
	}
	
	// less()、exch()和isSorted()方法见本文开头
}

上述是经典的插入排序实现代码,而插入排序代码改进可从下面两个方面进行:

  • 添加哨兵。先找出插入排序的最小元素置于数组最左边,这样就可以去掉内循环中 j>0 的判断条件。
  • 不使用交换。在插入排序的实现中使较大的元素右移一位只需访问一次数组(使用exch()方法则需要访问2次数组)。

改进后的插入排序实现如下所示:

public class InsertionX {

	public static void sort(Comparable[] a){
	    int n = a.length;
	    // 将最小的元素置于最左边作为哨兵
	    int exchanges = 0;
	    for (int i = n-1; i > 0; i--){
	        if (less(a[i], a[i-1])){
	            exch(a, i, i-1);
	            exchanges++;
	        }
	    }
	    // 如果没有发生过交换,说明数组本来就是有序的
	    if (exchanges == 0){
	        return;
	    }
	    // 将i之前的元素中,比a[i]大的元素往前推,直到找到
	    // 一个不大于a[i]的元素,将a[i]插入到该位置中
	    for (int i = 2; i < n; i++){
	        Comparable temp = a[i];
	        int j = i;
	        while (less(temp, a[j-1])){
	            a[j] = a[j-1];
	            j--;
	        }
	        a[j] = temp;
	    }
	    assert isSorted(a);
	}
	
	// less()、exch()和isSorted()方法见本文开头
}

根据笔者的测试结果,改进过后的插入排序速度大约为改进之前的1.2~1.5倍。

2.3 算法复杂度

对于随机排列的长度为   N \ N 且元素不重复的数组,平均情况下插入排序需要   N 2 / 4 \ N{^2}/4 次比较以及   N 2 / 4 \ N{^2}/4 次交换。最坏情况下需要   N 2 / 2 \ N{^2}/2 次比较以及   N 2 / 2 \ N{^2}/2 次交换,最好情况下需要   N 1 \ N-1 次比较和 0 次交换。

证明。我们同样可以通过一个   N N \ N✖N 的轨迹表得到比较和交换的次数。最坏的情况下对角线下的所有元素都需要移动位置,最好情况下都不需要。对于随机排列的数组,在平均情况下每个元素都有可能向后移动半个数组的长度,因此交总数是对角线之下的元素总数的   1 / 2 \ 1/2 。平均情况下的轨迹图如下所示:
Here Insert Picture Description

2.4 特点

从上面的分析我们可以得知,插入排序的比较和交换次数和数组中元素的初始顺序是有关的

  • 当输入的数组是完全倒序的如 [ I H G F E D C B A ],那么在循环中的每次扫描都会产生交换和元素的移动,此时它的比较次数和交换次数均为   N 2 / 2 \ N{^2}/2
  • 当输入的数组是完全有序的如 [ A B C D E F G H I ],那么在它就不需要进行任何交换操作,而它每次循环时的比较只会进行一次,因此它的比较次数为   N 1 \ N-1 ,交换次数为 0。
  • 当输入的数组是随机数组如 [ S O R T E X A M P L E ],它的比较和交换次数约为最坏情况下的一半,即比较次数和交换次数约为   N 2 / 4 \ N{^2}/4

接下来考虑一种部分有序的数组。

部分有序:如果数组中倒置的数量小于数组大小的某个倍数,那么这个数组就是部分有序的,下面是几种典型的部分有序数组:

  • 数组中的每个元素距离它的最终位置都不远;
  • 一个有序的数组接一个小数组;
  • 数组中只有几个元素的位置不正确。

倒置:数组中的两个顺序颠倒的元素。例如 E X A M P L E 有 11 对倒值:E-A、X-A、X-M、X-P、X-L、X-E、M-L、M-E、P-L、P-E 以及 L-E 。

对于部分有序的数组来说,插入排序的效果非常好,性能会非常接近于线性。事实上,当倒置的数量很少时,插入排序很可能是最优解的排序算法。

除此之外插入排序还很适合小规模数组,所以插入排序也会经常出现在其他高级排序算法的代码中,当高级排序算法的排序子数组小于某个阈值时,就会切换成插入排序。


3. 希尔排序

希尔排序是一种基于插入排序的快速的排序算法。对于大规模乱序数组插入排序很慢,因为它只会交换相邻的元素,因此元素只能一点一点地从数组的一端移动到另一端。而希尔排序为了加快速度对插入排序做了简单的改进,下面是它的思想。

3.1 思想

希尔排序的思想是使数组中任意间隔为h的元素都是有序的。在h很大时,就能将元素移动到很远的地方,为实现更小的h有序创造方便。用这种方式,对于任意以1结尾的h序列,我们都能将数组进行排序,这就是希尔排序。
Here Insert Picture Description
如上图,h=4时,数组中任何间隔为4的元素都是有序的。

3.2 代码实现

public class Shell {

    public static void sort(Comparable[] a){
        // 将a[]按升序排列
        int n = a.length;
        int h = 1;
        while (h < n/3) {
            h = 3 * h + 1;
        }
        while (h >= 1){
            // 将数组变为h有序
            for (int i = h; i < n; i++){
                // 将a[i]插入到a[i-h],a[i-2*h],a[i-3*h]...之中
                for (int j = i; j >= h && less(a[j], a[j-h]); j -= h){
                    exch(a, j, j-h);
                }
            }
            h = h/3;
        }
        assert isSorted(a);
    }
	
	// less()、exch()和isSorted()方法见本文开头
}

3.3 算法复杂度

希尔排序的复杂度无法精确地给出,目前已知的最重要的结论是:它的运行时间达不到平方级别。已知在最坏的情况下,上述代码的比较次数和   N 3 / 2 \ N{^{3/2}} 成正比。

3.4 特点

  • 希尔排序相比插入排序的最大优点是它可以用于大型数组;
  • 越是大型的数组,希尔排序相较于插入排序的优势就越大;
  • When Hill sorting medium-sized array sort its operating time is acceptable, its code is very small, and does not require additional space, other sorting algorithms may be advanced only 2 times faster than it, and More complex.

Third, the reference

  • "Algorithm", 4th Edition
    • Chapter 2 Sort
      • 2.1 Primary sorting algorithm

Guess you like

Origin blog.csdn.net/qq_38182125/article/details/94291446