插入排序

插入排序


  1/**
  2 * 插入排序的Java实现
  3 * <p>
  4 * 假设有数组a[N],插入排序的原理是:
  5 * <br>
  6 * 排序由N-1趟完成,从i = 1开始到N-1趟,插入排序保证从0到i-1位置上的元素是已排序的。
  7 * <br>
  8 * 因此第i趟时,只需要将位置i上的元素插入到已排序的元素中。
  9 * <p>
 10 * 假设有数组【34, 16, 25, 8, 56, 42, 17】,那么插入排序需要6趟,即可完成排序:
 11 * <table BORDER CELLPADDING=3 CELLSPACING=1>
 12 * <caption>插入排序的过程</caption>
 13 * <tr>
 14 * <td>原数组</td>
 15 * <td>34</td>
 16 * <td>16</td>
 17 * <td>25</td>
 18 * <td>8</td>
 19 * <td>56</td>
 20 * <td>42</td>
 21 * <td>17</td>
 22 * <td>移动的位置</td>
 23 * </tr>
 24 * <tr>
 25 * <td>第一趟</td>
 26 * <td>16</td>
 27 * <td>34</td>
 28 * <td>25</td>
 29 * <td>8</td>
 30 * <td>56</td>
 31 * <td>42</td>
 32 * <td>17</td>
 33 * <td>1</td>
 34 * </tr>
 35 * <tr>
 36 * <td>第二趟</td>
 37 * <td>16</td>
 38 * <td>25</td>
 39 * <td>34</td>
 40 * <td>8</td>
 41 * <td>56</td>
 42 * <td>42</td>
 43 * <td>17</td>
 44 * <td>1</td>
 45 * </tr>
 46 * <tr>
 47 * <td>第三趟</td>
 48 * <td>8</td>
 49 * <td>16</td>
 50 * <td>25</td>
 51 * <td>34</td>
 52 * <td>56</td>
 53 * <td>42</td>
 54 * <td>17</td>
 55 * <td>3</td>
 56 * </tr>
 57 * <td>第四趟</td>
 58 * <td>8</td>
 59 * <td>16</td>
 60 * <td>25</td>
 61 * <td>34</td>
 62 * <td>56</td>
 63 * <td>42</td>
 64 * <td>17</td>
 65 * <td>0</td>
 66 * </tr>
 67 * <td>第五趟</td>
 68 * <td>8</td>
 69 * <td>16</td>
 70 * <td>25</td>
 71 * <td>34</td>
 72 * <td>42</td>
 73 * <td>56</td>
 74 * <td>17</td>
 75 * <td>1</td>
 76 * </tr>
 77 * <td>第六趟</td>
 78 * <td>8</td>
 79 * <td>16</td>
 80 * <td>17</td>
 81 * <td>25</td>
 82 * <td>34</td>
 83 * <td>42</td>
 84 * <td>56</td>
 85 * <td>4</td>
 86 * </tr>
 87 * </table>
 88 *
 89 * <p>
 90 * 关于插入排序的复杂度分析,完全参考冒泡排序{@link BubbleSort}的分析过程。<br>
 91 * 插入排序也是稳定排序。
 92 * </p>
 93 *
 94 * @author wangy
 95 * @version 1.0
 96 * @date 2021/7/5 / 09:11
 97 */
 98public class InsertSort {
 99
100    // 通过比较->交换来排序
101    // 平均时间复杂度O(N^2)
102    static void sort(int[] a) {
103        for (int i = 1; i < a.length; i++) {
104            for (int j = 0; j < i; j++) {
105                // 元素交换
106                if (a[j] > a[i]) {
107                    int swap = a[j];
108                    a[j] = a[i];
109                    a[i] = swap;
110                }
111            }
112            System.out.println("===> " + Arrays.toString(a));
113        }
114    }
115
116    // 通过比较->移动来排序
117    // 时间复杂度 O(N^2)
118    // 性能更好的插入排序
119    static void sort2(int[] a) {
120        for (int i = 1; i < a.length; i++) {
121            int tmp = a[i];
122            int j;
123            for (j = i; j > 0 && a[j - 1] > tmp; j--) {
124                // 元素右移
125                a[j] = a[j - 1];
126            }
127            a[j] = tmp;
128            System.out.println("===> " + Arrays.toString(a));
129        }
130    }
131
132    /**
133     * <a href =
134     * "https://zh.wikipedia.org/wiki/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F">
135     * 希尔排序</a>
136     * <p>
137     * 简单讲,希尔排序是带<b>步长</b>的插入排序。
138     * <br>
139     * 希尔排序通过【h1, h2,...,hk】步长序列分别对数组中的元素进行插入排序。
140     * 步长序列是任意的,只要保证<code>h1 =1</code>即可。
141     * <br>
142     * 常用的步长序列(不是最好的)为 h(k) = h(k+1)/2,该序列的最坏时间复杂度为O(N^2)。
143     * <p>
144     * 关于复杂度的证明,稍微繁琐,此处不予讨论,仅给出代码实现
145     * </p>
146     */
147    static void shellSort(int[] a) {
148
149        for (int step = a.length / 2; step > 0; step /= 2) {
150            for (int i = step; i < a.length; i++) {
151                int temp = a[i];
152                int j = i - step;
153                while (j >= 0 && a[j] > temp) {
154                    a[j + step] = a[j];
155                    j -= step;
156                }
157                a[j + step] = temp;
158            }
159        }
160    }
161
162    public static void main(String[] args) {
163        int[] a = new int[] { 34, 16, 25, 8, 56, 42, 17 };
164
165        // InsertSort.sort(a);
166
167        InsertSort.shellSort(a);
168        System.out.println(Arrays.toString(a));
169    }
170}