插入排序:排序過的資料能顯著改善程式執行速度

陸超超發表於2012-02-20

1.概述

排序過的資料能顯著地改變程式的執行速度,因而在電腦科學中排序演算法是一類比較特別的東西。舉個例子,我們在有序連結串列中的搜尋要快於在無序連結串列中。

有兩種主要的排序方法——基於元素比較的方法與不基於元素比較的方法。在基於元素比較的方法中,最典型的就是插入排序。插入排序非常簡單,而且易於實現,但是遺憾的是,與其他諸如快速排序、歸併排序等排序演算法相比,它不是很有效。事實上,插入排序對那些元素不超過20個的小資料集來說還是很有用的。

插入排序是一種非常直觀的排序方法,我們大家玩撲克的時候就經常用到。玩家拿到一組無序的牌之後就會自然地開始對其排序。先取一張牌,通過若干次比較,然後將這張牌放到合適的位置上。

現在假設我們有一組資料。第一步剛開始時,該陣列中的資料是無序的,但是我們可以把這個陣列分成兩個部分:已排序的和未排序的,由於是剛開始排序,所以已排序的部分中僅有的一個元素就是陣列的第一個元素,陣列中的其餘元素均在未排序部分。如果陣列的長度是n,那麼該演算法會在接下來的(n-1)步內完成。在接下來的每一步,已排序的部分都會新增一個元素。在每一步中,演算法都會取出未排序部分的第一個元素,將該元素與已排序部分的元素進行若干次比較,然後插入已排序部分中合適的地方,如下圖所示:

enter image description here

插入操作本身是有技巧的。我們在已排序部分從後往前遍歷元素,一旦找到比要插入元素更小的元素或者已經遍歷到了陣列的最前端,那麼我就可以那裡插入元素了,如下圖所示:

enter image description here

2.實現

這裡是用PHP對插入排序的快速實現。插入排序的好處是易於實現,壞處是速度慢且對大資料集無效。

$data = array(4, 2, 4, 1, 2, 6, 8, 19, 3);

function insertion_sort(&$arr){
     $len = count($arr);

     for ($i = 1; $i < $len; $i++) {
          $tmp = $arr[$i];
          $j = $i;

          while (($j >= 0) && ($arr[$j-1] > $tmp)) {
                $arr[$j] = $arr[$j-1];
                $j--;
          }
          $arr[$j] = $tmp;
    }
}

為了減少一些元素比較的次數,我們可以使用一個哨兵來稍微提高一點程式碼的效率,就像順序搜尋一樣。

$data = array(4, 2, 4, 1, 2, 6, 8, 19, 3);

function insertion_sort_sentinel(&$arr){
       $len = count($arr);
       array_unshift(&$arr, -1); //新增哨兵

       for ($i = 1; $i < $len+1; $i++) {
            $tmp = $arr[$i];
            $j = $i;

            while ($arr[$j-1] > $tmp) {
                $arr[$j] = $arr[$j-1];
                $j--;
            }
            $arr[$j] = $tmp;
        }
        array_shift(&$arr); // 移除哨兵
 }

由於我們是在已排序的部分進行搜尋,很明顯可以用二分查詢法來提高上面演算法效能。但遺憾的是,這樣做並不能很明顯地提高插入排序演算法的總體效率。

3.複雜度

正如我前面所說,該演算法並非很有效。它的複雜度是enter image description here, 遠遠壞於複雜度為enter image description here的快速排序,如下圖所示:

enter image description here

4.應用

插入排序對小資料集是很有效的。即使插入排序並非是最有效的排序演算法,但是它也很有用,原因有如下三點:首先,該演算法易於實現;其次,它不需要額外的記憶體空間;最後,如果要排序的資料中大多數是有序的,那麼插入排序將會非常快,效率會非常高。

原文連結:Computer Algorithms: Insertion Sort

歡迎參加iTran樂譯4期

相關文章