標籤:效率 結果 直接選擇排序 相加 交換 func 插入排序 概念 base
1、冒泡排序
冒泡排序其實是基於“交換”。每次從第一個記錄開始,一、二兩個記錄比較,大的往後放,二三兩個記錄比較...依次類推,這就是一趟冒泡排序。每一趟冒泡排序後,無序序列中值最大的記錄冒到序列末尾,所以稱之為冒泡排序
| 123456789101112 |
function BubbleSort(&$_arr){ $len=count($_arr);<br> //外迴圈控制輪數 for($j=$len;$j>0;$j--){<br> //控制比較次數 for($i=0;$i<$j-1;$i++){ if($_arr[$i]>$_arr[$i+1]){ $temp=$_arr[$i]; $_arr[$i]=$_arr[$i+1]; $_arr[$i+1]=$temp; } } }} |
效率分析
相對於簡單選擇排序,冒泡排序交換次數明顯更多。它是通過不斷地交換把最大的數冒出來。
冒泡排序平均時間和最壞情況下(逆序)時間為o(n^2),最佳情況下雖然不用交換,但比較的次數沒有減少,時間複雜度仍為o(n^2)。此外冒泡排序是穩定的
2、選擇排序
給定待排序序列A[ 1......n ] ,選擇出第i小元素,並和A[i]交換,這就是一趟簡單選擇排序。固定值、然後交換索引
選擇排序的思想非常直接,不是要排序嗎?那好,我就從所有序列中先找到最小的,然後放到第一個位置。之後再看剩餘元素中最小 的,放到第二個位置……以此類推,就可以完成整個的排序工作了。可以很清楚的發現,選擇排序是固定位置,找元素。相比於插入排序的固定元素找位置,是兩種 思維方式。不過條條大路通羅馬,兩者的目的是一樣的
| 123456789101112131415 |
function SelectSort(&$_arr){ $len = count($_arr); for($i=0; $i<$len; $i++){ $k = $i; for($j=$i+1; $j<$len; $j++){ if ($_arr[$k] > $_arr[$j]) $k = $j; if ($k != $i){ $tmp = $_arr[$i]; $_arr[$i] = $_arr[$k]; $_arr[$k] = $tmp; } } }} |
效能分析
簡單選擇排序所需進行記錄移動的操作次數較少,這一點上優於冒泡排序,最佳情況下(待排序序列有序)記錄移動次數為0,最壞情況下(待排序序列逆序)記錄移動次數n-1。外層迴圈進行了n-1趟選擇,第i趟選擇要進行n-i次比較。每一趟的時間:n-i次的比較時間+移動記錄的時間(為一常數0或1,可以忽略)。總共進行了n-1趟。忽略移動記錄的時間,所以總時間為(n-1)*(n-i)=n^2-(i+1)*n+i。時間複雜度為O(n^2)。不管是最壞還是最佳情況下,比較次數都是一樣的,所以簡單選擇排序平均時間、最壞情況、最佳情況時間複雜度都為O(n^2)
直接選擇排序是一個就地排序,直接選擇排序是不穩定的
3、插入排序
給定待排序序列A[ 1.....n ],現假設A[1...i]已經有序,那麼我們取出A[i+1]插入到序列A[1...i].這樣有序序列記錄數就增加了1.如此重複上述操作,不斷取出記錄插入有序序列,直到A[n]插入到有序序列,排序完成
從有序序列的最後一個元素開始尋找,邊尋找邊移動元素,而不是先找到插入位置再移動元素,這樣提高了效率。
| 1234567891011121314 |
function InsertSort(&$_arr){ $len = count($_arr); for($i=1; $i<$len; $i++){ $tmp = $_arr[$i]; $j = $i-1; while($_arr[$j] > $tmp && $j>=0){ $_arr[$j+1] = $_arr[$j]; $_arr[$j] = $tmp; $j--; } }} |
效率分析
容易看出,要插入的記錄個數為n-1,其中關鍵字的比較次數和記錄移動次數是依賴於給出的待排序序列是否基本有序。在最佳情況下(待排序序列有序),比較次數和移動次數時間為o(1),所以時間複雜度為o(n).在最壞情況下(待排序序列逆序)和平均時間均為o(n^2).從上述分析中可以看出,直接插入排序適合記錄數比較少、給定序列基本有序的情況。熟悉了排序過程我們發現,直接插入排序是一種穩定的原地排序演算法
4、快速排序
快速排序是冒泡排序的一種改進,冒泡排序排完一趟是最大值冒出來了,那麼可不可以先選定一個 值,然後掃描待排序序列,把小於該值的記錄和大於該值的記錄分成兩個單獨的序列,然後分別對這兩個序列進行上述操作。這就是快速排序,我們把選定的那個值 稱為樞紐值,如果樞紐值為序列中的最大值,那麼一趟快速排序就變成了一趟冒泡排序
| 12345678910111213141516171819202122 |
function QuickSort($_arr){ $len=count($_arr); if($len <= 1) return $_arr; $base = $_arr[0]; $left_arr =$right_arr=array(); for($i=1; $i<$len; $i++){ if($_arr[$i]<= $base){ $left_arr[]=$_arr[$i]; }else{ $right_arr[]=$_arr[$i]; } } $left_arr=QuickSort($left_arr); $right_arr=QuickSort($right_arr); $arr=array_merge($left_arr, array($base), $right_arr); return $arr;} |
效率分析
最佳情況下,每次劃分都是對稱的,由於樞紐值不再考慮,所以得到的兩個子問題的大小不可能大於n/2,同時一趟快速排序時間為o(n),所以已耗用時間遞迴運算式:T(n)<=2T(n/2)+o(n)。這個遞迴式的解法請參考下一篇部落格中歸併排序效率分析。其解為T(n)=o(n*logn)。
最壞情況下,每次劃分都很不對稱,T(n)=T(n-1)+o(n),可以用遞迴樹來解,第i層的代價為n-i+1.總共有n層。把每一層代價加起來有n-1個n相加。所以這個遞迴式的解為T(n)=o(n^2),此時就是冒泡排序。
還有兩個概念要瞭解一下
1. 內排序和外排序
內排序,參加排序的資料量不大,在排序過程中可以將所有參加排序的資料存放在記憶體中處理的排序方法。
外排序,參加排序的資料量很大,以至於記憶體不足以一次存放全部資料,在排序過程中需要通過記憶體與外存之間的資料交換來達到排序目的的排序方法。
2. 穩定性排序與非穩定性排序
參加排序的項稱為排序碼或者排序項。
這個概念是針對的是有多個相同的排序項參加排序的情況。
若採用排序方法排序後這些相同的排序項的相對位置與排序之前保持不變,則稱此排序方法是穩定性排序,否則為非穩定性排序。
例如,參加排序的依次是:a1 = 3, a2 = 6, a3 = 18, a4 = 3, a5 = 18;
若是穩定性排序,則排序結果一定是:
a1 = 3, a4 = 3, a2 = 6, a3 = 18, a5 = 18;
若是非穩定性排序,則排序結果可能會是:
a4 = 3, a1 = 3, a2 = 6, a3 = 18, a5 = 18;
這樣a1 和a4 的相對位置改變。
PHP實現4種排序演算法