前言
關於對數組的排序,在算法中有很多方法,較爲簡單的有冒泡,選擇,插入等一些使人熟知的算術方法,在當今這個追求效率的社會,算法的好壞對程序本身有着重要的影響。而我們在判定算法好壞的時候,時間複雜度是一個重要的標尺,
而對數組排序中,插入排序和快速排序的效率要比冒泡和選擇排序的效率要高,而今天就來聊一聊插入排序和快速排序的原理和實現。
插入排序
插入排序的基本操作就是將一個數據插入到已經排好序的有序數據中,從而得到一個新的有序數據,把排序的數組分成兩部分:第一部分包含了這個數組的所有元素,但將最後一個元素除外(讓數組多一個空間纔有插入的位置),而第二部分就只包含這一個元素(即待插入元素)。在第一部分排序完成後,再將這個最後元素插入到已排好序的第一部分中。
原理示意圖
通俗易懂的說就是:
我們在對數組進行排序是,可以將數組的第一個數字看成是一個有序的數組,而後面的數字是一個無序的數組。遍歷後面的無序數組和前面有序的數組進行比較,當發現需要插入時,有序數組向後挪移一位,插入數據。
案列(從小到大排序):
有一個數組:
$arr = array(1,2,10,5,3);
假設第一個數1是有序數組。即:
有序(1)無序(2 , 10 , 5 , 3);
遍歷無序數組
for($i = 1; $i < $total; $i++){
$insert = $arr[$i];//先記錄帶插入的數據;
$j = $i - 1;
利用while循環進行判斷插入的位置
while($j >= 0 && $arr[$j] > $insert){
判斷條件$j必須大於等於0,當前面已排完序的數比待排序的數大,這是就需要先前的數向後挪一位即:
$arr[$j + 1] = $arr[$j];
$j--;
在這裏不要擔心$arr[$i]被覆蓋了,我們已經在for循環之後記錄的待排序的數值。
當不滿足while的循環判斷條件的時候跳出循環,並賦值
$arr[$j + 1] = $insert;
在這裏可以進行判斷當沒有進入循環的時候,$j + 1 = $i 這時不用進行賦值。
代碼:
<?php
$arr = array(1,2,10,5,3);
function insertSort(&$arr){
$total = count($arr);
for($i = 1; $i < $total; $i++){
$insert = $arr[$i];//先記錄帶插入的數據;
$j = $i - 1;
while($j >= 0 && $arr[$j] > $insert){
$arr[$j + 1] = $arr[$j];
$j--;
}
if($j +1 != $i){
$arr[$j + 1] = $insert;
}
}
}
insertSort($arr);
echo '<pre>';
var_dump($arr);
數字流程示意圖:
插入排序的時間複雜度爲O(n^2)。是穩定的排序方法。
快速排序
通過一趟排序將要排序的數據分割成獨立的兩部分,其中一部分的所有數據都比另外一部分的所有數據都要小,然後再按此方法對這兩部分數據分別進行快速排序,整個排序過程可以遞歸進行,以此達到整個數據變成有序序列。
快速排序的示例:
有一個數組:
$arr = array(6,2,7,3,8,9);
我們選取第一個數字爲界:
$k=$arr[0];//記錄k的值 把數組分成兩個部分,比k小的在左邊,比k大的在右邊。
定義兩個數組一個存儲比k小的數的值,一個存儲比k大的值。
然後遍歷數組,和$k的值進行比較,遍歷完成後,使用遞歸,不斷的分解數組,直到不能再分解爲止。
$x=quickSort($x);
$y=quickSort($y);
return array_merge($x,array($k),$y);//數組合並。
代碼(易於理解的一種寫法):
<?php
$arr = array(6,2,7,3,8,9);
function quickSort(&$arr){
if(count($arr)>1){
$k=$arr[0];//記錄k的值 把數組分成兩個部分,比k小的在左邊,比k大的在右邊。
$x=array();
$y=array();
$_size=count($arr);
for($i=1;$i<$_size;$i++){
if($arr[$i]<=$k){
$x[]=$arr[$i];
}else if($arr[$i]>$k){
$y[]=$arr[$i];
}
}
$x=quickSort($x);
$y=quickSort($y);
return array_merge($x,array($k),$y);//數組合並。
}else{
return $arr;
}
}
echo '<pre>';
var_dump(quickSort($arr));
(注意:這種方法雖然符合快速排序的思想,但是會在遞歸過程中創建大量的數組存放數據,當數據量大的時候會造成 Allowed memory size of 134217728 bytes exhausted也就是內存耗盡)
總結
插入排序和快速排序的差別:插入排序的效率比快速排序的效率要低。我們可以用一個存放20萬個數據數組,使用兩種方法進行比較。
<span style="font-size:18px;"> $arr = array();
for($i = 0; $i < 200000; $i++){
$arr[] = rand(1, 3000);
}</span>
通過執行前後時間的對比
插入排序:
快速排序:
可以看出插入排序的執行時間超過了php的默認時間。而快速排序用了7秒