title: 重整算法第三天:插入排序
date: 2019-04-11
tags: 算法
重整算法第三天:插入排序
在計算機的實現中,爲了給要插入的元素騰出空間,我們需要將其餘所有元素在插入之前都向右移動一位。這種算法叫做插入排序
與選擇排序一樣,當前索引左邊的所有元素都是有序的,但它們的最終位置還不確定,爲了給更小的元素騰出空間,它們可能就會被移動。但是當索引到達數組的右邊時,數組排序就完成了。
和選擇排序不同的是,插入排序所需的時間取決於輸入中元素的初始順序。
例如:對一個很大且其中國的元素已經有序(或接近有序)的數組進行排序將會比對隨機順序的數組或是逆序數組進行排序要快得多。
對於隨機排列的長度爲N且主鍵不重複的數組,平均情況下插入排序需要~N2/4次比較以及~N2/4次交換。最壞情況下需要~N2/2次比較和~N2/2次比較,最好情況下需要N-1次比較和0次交換。
插入排序代碼如下:
package com.lagoon.sort;
/**
* @Author WinkiLee
* @Date 2019/4/11 9:44
* @Description
*/
public class InsertSort {
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]....中
//如果當前a[i]能在左側插入,也就是較小的話
for (int j=i;j>0 && less(a[j],a[j-1]);j--){
exch(a,j,j-1);
}
}
}
/**
* 比較大小
* @param v
* @param w
* @return false or true
*/
private static boolean less(Comparable v,Comparable w){
return v.compareTo(w)<0;
}
/**
* 交換數
* @param a
* @param i
* @param j
*/
private static void exch(Comparable[] a,int i,int j){
Comparable t=a[i];
a[i]=a[j];
a[j]=t;
}
/**
* 打印結果
* @param a
*/
private static void show(Comparable[] a){
//在單行中打印數組
for (int i=0;i<a.length;i++){
System.out.print(a[i]+"");
}
System.out.println("");
}
/**
* 測試元素數組是否有序
* @param a
* @return true or false
*/
public static boolean isSorted(Comparable[] a){
//測試元素數組是否有序
for (int i=1;i<a.length;i++){
if (less(a[i],a[i-1])){
return false;
}
}
return true;
}
/**
* main方法及測試
* @param args
*/
public static void main(String[] args) {
Comparable[] a ={6,4,1,3,5,9,7,8,2};
Comparable[] b ={'a','e','w','p','s','b','q'};
sort(a);
sort(b);
show(a);
show(b);
}
}
測試結果:
有以下幾種典型的部分有序數組:
- 數組中的每個元素距離它的最終位置都不遠
- 一個有序的大數組接一個小數組
- 數組中只有幾個元素的位置不正確
插入排序對這樣的數組很有效,而選擇排序則不然。事實上,當倒置的數量很少時,插入排序很可能比其他任何算法都要快
插入排序需要的交換操作和數組中倒置的數量相同,需要的比較次數大於等於倒置的數量,小於等於倒置的數量加上數組的大小再減一
倒置指的是數組中兩個順序顛倒的元素。例如EXAMPLE中有11對倒置,E-A, X-A, X-M, X-P, X-L, M-E, P-L, P-E, L-E.
如果數組中倒置的數量小於數組大小的某個倍數,可以說這個數組就是部分有序的
要大幅提高插入排序的速度並不難,只需要在內循環中將較大的元素都向右移動而不總是交換兩個元素(這樣訪問的數組就能減半)。
總的來說插入排序對於部分有序的數組十分高效,也很適合小規模數組,這很重要,因爲這些類型的數組在實際應用中經常出現。