久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

插入排序與希爾排序

 昵稱11350173 2012-12-24
首發(fā)傳智播客IT論壇:http://bbs./thread-7315-1-1.html

先來插入排序:
假設(shè)我們需要排序的序列:
4
7
6
3
9
5
8
我們的排序思路是:
先,,將序列分成兩部分,一部分為排序好的序列,,另一部分為未排序的序列,,例如:
4
6
7
3
9
5
8
其中 橙色的 4,6,,7 是第一部分已經(jīng)排序好的序列,;黑色的3,9,,5,,8為第二部分,需要排序的部分,。

其次,,在第二部分為排序序列內(nèi)取得一個元素,然后將其插入到這個已經(jīng)排序好的序列內(nèi),,例如:
將 3  插入到 4,,6,7這個序列內(nèi),,插入的結(jié)果為:
3
4
6
7
9
5
8
這樣 排序好的第一部分就變成了3,,4,6,,7,;第二部分就變成了 9,5,8,。

再次:這樣 以此類推,,將 所有未排序序列中的元素 依次插入到這個排序好的序列內(nèi)。當(dāng)所有的未排序元素都插入成功后,,我們的排序好的序列就是我們需要的排序結(jié)果,。例如:
將9插入:
3
4
6
7
9
5
8
將5插入:
3
4
5
6
7
9
8
將8插入:
3
4
5
6
7
8
9

排序就成功了。
由于每次都是將一個元素插入到 排序好的序列中,,因此這個排序算法稱之為 插入排序,。

算法的思路就是這樣了,可能大家會問:我們第一次是如何將一個序列拆分成兩個部分的呢,?也就是如何得到:
3
4
6
7
9
5
8
這個序列的呢,?
其實很簡單,我的說明是假設(shè)排序好的序列內(nèi)已經(jīng)存在了3個元素,,大家可以試想,,當(dāng)我們第一次將序列分成兩部分時,我們可以認(rèn)為 第一部分排序好的序列內(nèi)只有一個元素,,而其余的都在第二部未排序的序列內(nèi),,就是:
4
7
6
3
9
5
8
大家可以看到 當(dāng)只有一個元素時,那么這個序列就是一個排序好的序列了吧,。
因此我們需要做的第一件事情就是 將 7 插入到4這個序列內(nèi),,結(jié)果為:
4
7
6
3
9
5
8
下面的事情大家就應(yīng)該清楚了吧,依次操作即可,。

哦了,,下面我們看看利用程序代碼如何實現(xiàn):
編程思路是這樣的,,使用雙重循環(huán)完成,,外層控制需要插入的元素,而內(nèi)層控制每次插入時參與比較的元素,。function insert_sort(&$arr) {
    for($i=1, $len=count($arr); $i<$len; $i++) {
        $tmp = $arr[$i];
        for($j=$i-1; $j>=0 && $tmp < $arr[$j]; $j--) {
            $arr[$j+1] = $arr[$j];
        }
        $arr[$j+1] = $tmp;
    }
}
上面的代碼使用了引用傳遞 ,。

經(jīng)過上面的處理就完成了 插入排序。

接下來,,簡單的分析一下這個算法,。
在最好的情況下,也就是輸入的序列本身也就是一個排序好的序列,,那么這個算法的運行時間為O(N),,因為內(nèi)層循環(huán)總是檢測到break的情況。
但是如果輸入的序列是一個逆序(就是從大到小的序列),,那么執(zhí)行的次數(shù)為1+2+,。。+N,,因此運行的時間為O(N^2),。
可以看出來,,這個算法的執(zhí)行時間的差別很大,執(zhí)行時間取決于待排序序列中存在多少個逆序,。

由此可知,,當(dāng)需要排序的序列是一個幾乎被排序的序列(序列中的逆序較少)時,插入排序的效率還是相當(dāng)可觀的,。

就說到這,,引玉之磚,大家討論,。
還有一個希爾排序,,也類似與插入排序,相當(dāng)一個分組的插入排序,,接下來會介紹,。

希爾排序,這個名稱源于希爾排序的發(fā)明者Donald Shell,。

還是先說希爾排序的思路:
希爾排序的大體思路是:將一個未排序的序列分成多個組,,然后在組內(nèi)使用插入排序?qū)M內(nèi)序列排序。我們的分組方式是將每隔固定位置(增量)的元素分成一組,。之后去調(diào)整這個間隔大小,,重新分組,組內(nèi)重新排序,。直到分組的間隔為1,,也就是所有的元素分成一組,再進行一次插入排序,,這樣就可以完成整個序列的排序過程,。

下面描述以下這個過程:
假設(shè)我們需要排序的序列:
4
7
6
3
9
5
8
先將我們的序列分成幾組,例如我們將每隔三個分成一組,,那么分組的結(jié)果為:
4
7
6
3
9
5
8
然后我們在組內(nèi)進行排序,,排序的結(jié)果為:
3
7
5
4
9
6
8
從結(jié)果上看,我們可以發(fā)現(xiàn) 每一組內(nèi)的數(shù)據(jù)是按照順序排序的,,大家注意一個顏色的就是一個分組,。

然后重新進行分組,例如分組的間隔改為了 2,,那么分組的結(jié)果為:
3
7
5
4
9
6
8
在組內(nèi)排序:結(jié)果為:
3
4
5
6
8
7
9


再次分組,,標(biāo)準(zhǔn)為間隔為 1,那么分組結(jié)果為所有都是一組,,然后在組內(nèi)排序:
結(jié)果為:
3
4
5
6
7
8
9
這樣 經(jīng)過這么幾輪后,,排序的效果就出來了。
注意,我們在組內(nèi)進行排序時,,是采用的插入排序算法(可以參考另一個貼子介紹插入排序),。

看到這 可能會有些問題了,一個比較鮮明的就是:既然組內(nèi)排序采用的是插入排序,,而且我們最后也要將所有的元素分成一組,,那不是相當(dāng)于最后做了一次插入排序么,而且要比正規(guī)的插入排序,,多出了好多輪其他分組情況的組內(nèi)排序,,為什么還有有真?zhèn)€排序方式呢?
大家還記不記得我們說插入排序后有一個小討論了,,具體可看插入排序介紹,。我們討論的結(jié)論是:插入排序的最好情況(沒有逆序)時的復(fù)雜度為O(N),而最壞情況(逆序為N*(n-1)/2)的復(fù)雜度為O(N^2),。 基于這個結(jié)論,,大家可以發(fā)現(xiàn),我們在最后一次分成一組時,,序列內(nèi)的逆序(大數(shù)在小數(shù)前的兩個數(shù)的組合,,例如8,7)已經(jīng)非常少,我么的例子中就一個,,因此這個效率是很高的,,要比直接進行插入排序的效率高呢。

大家還需要注意,,注意以上的示例中,,我使用的分組間隔為 3, 2, 1 。其實這個序列是任何最后一個元素為1的序列都可以,。例如3,,1 或者 4,2,,1都可以,。但是一定注意不同的序列產(chǎn)生的排序復(fù)雜度是不一樣的,,切記,。
這個分組序列稱之為希爾排序的增量序列,增量序列有一個非常流行的選擇稱之為希爾增量(希爾這個人建議的增量序列):假設(shè)序列為ht...hk hk-1 .. h1 ,,排序序列的長度為N,,那么ht = N除以2的商, 而hk-1 = hk 除以2的商,,直到h1 = 1;
例如如果待排序數(shù)組的長度為 10,,那么序列為 5, 2, 1;

下面我們就使用這個希爾增量來編寫希爾排序的程序:
看代碼,代碼的實現(xiàn)步驟為:使用三層循環(huán)達到目的,最外層控制循環(huán)增量的值,,里面兩層使用插入排序的方法完成排序:
  1. function shellSort(&$arr) {
  2.     $len = count($arr);
  3.     //確定增量序列
  4.     //php內(nèi)沒有整除 采用floor向下去整
  5.     for($inc=floor($len/2); $inc>=1; $inc=floor($inc/2)) {
  6.         //內(nèi)部實現(xiàn)與插入排序類似
  7.         //不過比較的元素取決于增量
  8.         for($i=$inc; $i<$len; ++$i) {
  9.             $tmp = $arr[$i];
  10.             for($j=$i-$inc; $j>=0 && $tmp<$arr[$j]; $j-=$inc) {
  11.                 $arr[$j+$inc] = $arr[$j];
  12.             }
  13.             $arr[$j+$inc] = $tmp;
  14.         }
  15.     }
  16. }
復(fù)制代碼
上面的代碼就實現(xiàn)了一個基于希爾增量的希爾排序,。

還有需要大家注意,雖然在示例代碼內(nèi),,我們使用的是希爾增量(感覺好像最正宗),,但是在實際的操作中,希爾增量并不是一個最好的增量序列,,比較常用的其他序列有:
希爾增量(程序里使用的):N/2   N/2/2  N/2/2 N/2/2../2  1  (/為整除的意思),,這個增量的最壞情形是O(N^2);
Hibbard增量:2^k - 1 ,2^k-1 - 1, .... 2^2 - 1 , 2^1 -1,;這個增量的最壞情形是O(N^3/2)
還有一個被認(rèn)為是目前最好的增量序列:.... 109, 41, 19, 5, 1 其中每項是9*4^i - 9*2^i + 1與 4^i - 3*2^i + 1值內(nèi)比較小的一個,。
但是還有可能出現(xiàn)更好是序列,應(yīng)該是數(shù)學(xué)問題了,。
大家如果希望使用其他序列作為程序?qū)崿F(xiàn),,大可以將這個序列放入一個數(shù)組內(nèi),然后將最外層循環(huán)改為遍歷這個序列,,然后達到目錄:
例如:
  1. function shellSort(&$arr) {
  2.     $len = count($arr);
  3.     //確定增量序列
  4.     //php內(nèi)沒有整除 采用floor向下去整
  5. //    for($inc=floor($len/2); $inc>=1; $inc=floor($inc/2)) {
  6.     $sequence = array(41, 19, 5 ,1);//設(shè)置序列,,可以換成別的序列
  7.     //遍歷序列
  8.     for($k=0,$leng=count($sequence); $k<$leng; $k++) {
  9.         $inc = $sequence[$k];
  10.         //內(nèi)部實現(xiàn)與插入排序類似
  11.         //不過比較的元素取決于增量
  12.         for($i=$inc; $i<$len; ++$i) {
  13.             $tmp = $arr[$i];
  14.             for($j=$i-$inc; $j>=0 && $tmp<$arr[$j]; $j-=$inc) {
  15.                 $arr[$j+$inc] = $arr[$j];
  16.             }
  17.             $arr[$j+$inc] = $tmp;
  18.         }
  19.     }
  20. }
復(fù)制代碼
上面的代碼就是更改和增量序列的部分,其余的不變,。
如果增量序列只有一個1,,那么就變成了插入排序了。

對了,,由于每一輪比較時所采用的增量序列內(nèi)的值都是在逐漸減小,,因此這個希爾排序也被稱之為縮小增量排序。

ok,,就到這,。引玉之磚,歡迎討論,。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多