2021-02-08

 

记录今天的“算法第四版”进度

今天学习的内容有:插入排序(insertion sort)和希尔排序(shell sort)讲解了排序的一个应用,洗牌(shuffling),那么下面我将简单的总结下今天的学习内容,当作一种记录和复习。

插入排序(Insertion sort)

与选择排序不一样,插入排序不需要做非常多次比较操作,而是需要做更多次换位操作,选择排序对于已经排列好的一组数据进行排序和完全打乱的数据进行排序,其花费的时间是没有差别的,但是插入排序考虑到了数组本身并不完全是无序的,其中有原本就是顺序的数据,也有逆序的数据,其中逆序的数据越多,插入排序所需要花费的时间越久。

因此,在插入排序中,我们需要做的事情有:

  1. 将索引定在数组的n=1的位置上,遍历整个数组
  2. 在第一个循环内,将第n个索引所对应的数据与前一个进行比较,如果逆序就进行交换,直到第一个数据,此时n之前的数据已经是有序的。
public class Insertion 
{ 
 public static void sort(Comparable[] a) 
 { // 将a[]按升序排列
 int N = a.length; 
 for (int i = 1; i < N; i++) 
 { // 将 a[i] 插入到 a[i-1]、a[i-2]、a[i-3]...之中
 for (int j = i; j > 0 && less(a[j], a[j-1]); j--)
 exch(a, j, j-1); 
 } 
 } 

}

可视化如下:

2021-02-08_第1张图片

希尔排序(Shell sort) 

那么还有什么方法可以缩减运算量呢?我们注意到插入排序其实做了很多没有必要或者说是多余的换位操作,有些元素的位置本来就是正确的。

希尔排序的思想是使数组中任意间隔为 h 的元素都是有序的。这样的数组被称为 h 有序数组 。换句话说,一个 h 有序数组 就是 h 个互相独立的有序数组编织在一起组成的一个数组。在进行排序时,如果 h 很大,我们就能将元素移动到很远的地方,为实现更小的 h 有序 创造方便。
2021-02-08_第2张图片 h有序数组

 

我们注意到一个非常有意思的性质,比如说我们先对一组数据进行h=7的有序排列 ,再进行h=3的有序排列,那么此时的排列对于h=7的情况来说依旧是有效的。按照h=3x+1的办法来进行h有序数组排序,就可以节省很大一部分的交换操作,减少实际的操作时间。

代码如下(摘自算法第四版)

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; // 1, 4, 13, 40, 121, 364, 1093, ... 
 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; 
 } 
 }
 // less()、exch()、isSorted()和main()方法见“排序算法类模板”
}

希尔排序的可视化

2021-02-08_第3张图片

 洗牌今天懒得写了。

你可能感兴趣的:(算法4笔记)