3、由java實現的簡單算法——插入排序

一  前言

如果對本系列產生什麼疑問的話,  建議先下前言,  裏面有我的聯繫方式,  教材的下載地址,   特殊詞語的規定之類的........   鏈接地址: https://blog.csdn.net/qq_41057280/article/details/89209081 ;   最後, 以下說法僅爲個人理解, 如有錯誤, 歡迎教正

二  介紹

插入排序, 全名 直接插入排序算法(Insertion sort),  <<算法導論>>原文介紹如下: 

我翻譯一下這段話,  插入算法, 就是一個能在一個有序數列中插入一個數,保證插入後此數列仍然有序的排序算法.  適用於數據量級較小的情況.  

是不是感覺不太對, 畢竟他的原文和我的翻譯完全不一致.   原文是給大家舉了個例子, 一個拿牌的案例,這個案例生動形象地介紹了插入排序的原理,簡單系統地說明了插入排序基本實現步驟, 能幫助大家快速理解和掌握該算法.   但是,  如果有天要你回答插入算法是什麼,  你總不能跟他說是怎麼怎麼拿牌的吧~~

所以, 在此我就直接忽略原文概括一下. 

三  僞代碼

 

這是<<算法導論>> 提供的插入算法的僞代碼,  由於是第一個僞代碼, 所以就詳細談談該怎麼理解這段僞代碼

  1.   第一行,  for循環, 索引 "j" 從2開始遍歷數組A,   這裏的"2"是指第二個元素
  2.   第二行,  獲取當前索引 "j" 得到的數組值存與變量key
  3.   第三行,  註釋,  該行說明不參與運算,  說明數組A的索引是1開始, 而不是0
  4.   第四行,  得到當前索引的上一個元素索引  "i"  
  5.   第五、六、七行,  while倒序循環,  把比key大的已排序的數據後移一位
  6.   第八行,  將key放入空出來的位置

以上就是插入算法的核心實現思路,  從第二個元素開始插入,  倒序循環並按照排序規則後移元素,  保證位置能空出一位, 直到退出循環,  將元素插入空出來的位置

不清楚怎麼看僞代碼的朋友,  可以看看我寫的僞代碼規則 https://blog.csdn.net/qq_41057280/article/details/90176737 

四  java實現

好了,  重頭戲來了.  首先,  先來個常規的照着僞代碼寫.

/**
* 插入排序 ,  這裏把變量名儘量與僞代碼統一,  方便大家查看    
*/
public void insertSort(int[] A) {
    int n = A.length;
    for (int j = 1; j < n; j++) {
        int key = A[j];
        int i = j - 1;
        while (i >= 0 && A[i] > key) {
            A[i + 1] = A[i]; // 比key大的已排序數據後移一位
            i--;
        }
        A[i + 1] = key; // 空出來的位置,把key放進去
    }
}

就把僞代碼換成java代碼即可,  唯一要注意的就是數組索引,  在僞代碼裏面數組下標是從1開始,  而java是從0開始.  所以 while的判斷和  j 的初始值,  都要做點改動

五  基於插入算法實現的數組

按照插入算法的定義,  該算法存在保證數組在插入數據後依舊有序的特性,  如果把該特性運用在數組中, 不就可以實現一個自動排序的數組

代碼如下,   重點在insert方法,   上面插入算法是倒序遍歷,  這次用正序遍歷,  其餘邏輯一致.  之所以換種寫法, 純粹就是閒起來了(滑稽)

class InsertArray{
    private int length;
    private Integer[] arr;
    
    public InsertArray() {
        arr = new Integer[50];
    }
	
    public InsertArray(int length) {
        arr = new Integer[length];
        this.length = length;
    }
	
    /**
     * 添加數據
     */
    public void insert(int value) {
        int i;
        // 從前往後遍歷,  找到value的位置
        for(i = 0; i < length; i++) {
            if(arr[i] > value) {
                break;
            }
        }
        // 將所有比value大的元素,後移一位
        for(int j = length; j > i; j--) {
            arr[j] = arr[j - 1];
        }
        arr[i] = value;
        length++;
    }
	
    /**
    * 重寫toStirng,用於數據展示
    * @return 
    */
    public String toString() {
        return Arrays.stream(arr)
                .filter(e -> e != null)
                .map(e -> e.toString())
                .collect(Collectors.joining(","));
    }
}

然後測試一下

嗯,  看來是成功了

六   二分插入排序

最後, 我再引申一個插入排序算法的變種,  二分插入排序 .  與直接插入的區別,  就是在搜索數據插入位置, 採用二分法進行搜索,  這樣可以有效的減少比較次數.   僅此而已,  可惜時間複雜度還是O(n²).   代碼複雜,  提升的是無關緊要的效率.  數據量級一大,  該慢還是慢.  評價.  雞肋

/**
* 二分法插入排序
*/
public static void binaryInsertSort(int[] arr) {
    int n = arr.length;
    
    for (int i = 1; i < n; i++) {
        int key = arr[i];
	
        int right = i - 1;
        int left = 0;
			
        while (left <= right) {
            int mid = (left + right) / 2;
	
            if (key < arr[mid]) {
            	right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
			
        for (int j=i; j>left;j--) {
            arr[j] = arr[j - 1]; // 比key大的已排序數據後移一位
        }
        arr[left] = key; // 空出來的位置,把key放進去
    }
}

七   總結

插入排序, 是一個很簡單的排序算法.  他在數據量級較小或者數據基本有序的時候推薦使用.   話是這麼說,  其實沒啥人使用(笑~~)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章