以前讀劉未鵬的《暗時間》裏面就有這樣一個觀點「互聯網技術突飛猛進,程序員要學的技術變化的很快,但真正不變的東西其實不多,好比數據結構和算法」,php
原文請訪問番茄技術小站程序員
先作一些,準備工做,好比生成排序算法須要的隨機數組、數組元素交換、測試排序算法的性能、生成基本有序的數據等函數算法
<?php
/** * 排序算法幫助函數 * @author junqi1 <2018-1-7> */
/** * [generateRandomArray 生成有n個元素的隨機數組,每一個元素的隨機範圍爲[rangeL, rangeR]] * @param [type] $n [description] * @param [type] $rangeL [description] * @param [type] $rangeR [description] * @return [type] [description] */
function generateRandomArray($n, $rangeL, $rangeR) {
assert($rangeL < $rangeR);
$arr = array();
for ($i = 0; $i < $n; $i++){
$arr[$i] = rand($rangeL, $rangeR);
}
return $arr;
}
/** * [generateNearlyOrderedArray 產生n個幾乎有序的數組, ] * @param [type] $n [description] * @param [type] $swapTimes [順序數組中調換的個數] * @return [type] [description] */
function generateNearlyOrderedArray($n, $swapTimes){
$arr = array();
for ($i=0; $i < $n; $i++) {
$arr[$i] = $i;
}
//調換數組
for ($i=0; $i < $swapTimes; $i++) {
$swap1 = rand(0, $n-1);
$swap2 = rand(0, $n-1);
swap($arr, $swap1, $swap2);
}
return $arr;
}
//數組元素交換
function swap(&$arr, $i, $j){
$tmp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $tmp;
}
function isSort($arr, $n){
for ($i=0; $i < $n-1; $i++) {
if ($arr[$i] > $arr[$i+1]) {
return false;
}
}
return true;
}
//測試排序算法的性能
function testSort($sortName, $sorFunction, $arr, $n){
$t1 = microtime(true);
$sorFunction($arr, $n);
$t2 = microtime(true);
assert(isSort($arr, $n), "排序算法錯誤!\n");
echo "{$sortName}運行的時間爲:". (($t2-$t1)).'s'."\n";
}
複製代碼
選擇排序(Selection sort)是一種簡單直觀的排序算法。它的工做原理以下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,而後,再從剩餘未排序元素中繼續尋找最小(大)元素,而後放到已排序序列的末尾。以此類推,直到全部元素均排序完畢。數組
<?php
require('../Library/SortTestHelper.php');
/** * [selectSort 選擇排序] * @param [type] &$arr [description] * @param [type] $n [description] * @return [type] [description] */
function selectSort(&$arr, $n){
for($i = 0; $i < $n; $i++){
$minIndex = $i;
for ($j=$i + 1; $j < $n; $j++) {
if ($arr[$j] < $arr[$minIndex]) {
swap($arr, $minIndex, $j);
}
}
}
}
//main
// $n = 100;
// $arr = generateRandomArray($n, 0, $n);
// testSort("selectSort", "selectSort", $arr, $n);
複製代碼
現實生活中,整理撲克牌撲克牌其實就是插入排序的應用服務器
插入排序(英語:Insertion Sort)是一種簡單直觀的排序算法。它的工做原理是經過構建有序序列,對於未排序數據,在已排序序列中從後向前掃描,找到相應位置並插入。在從後向前掃描過程當中,須要反覆把已排序元素逐步向後挪位,爲最新元素提供插入空間。微信
/** * [insertSort 插入排序] * @param [type] &$arr [description] * @param [type] $n [description] * @return [type] [description] */
function insertSort(&$arr, $n){
//從第2個元素開始,找尋它的位置,因此從i=1開始
for ($i=1; $i < $n; $i++) {
//從第1個元素到第i個元素之間,尋找arr[i]的位置, j>0表示,最終比較的是第1個元素和第0個元素
//第一種寫法
// for ($j=i; $j > 0 ; $j--) {
// if ($arr[j-1] > arr[j]) {
// swap($arr, $j-1, $j);
// }else{
// break;
// }
// }
//第二種寫法:更簡潔
for ($j=$i; $j > 0 && $arr[$j-1] > $arr[$j]; $j--) {
swap($arr, $j-1, $j);
}
}
}
複製代碼
運行時間數據結構
//main
$n = 10000;
// $arr = generateRandomArray($n, 0, $n);
$arr = generateNearlyOrderedArray($n, 100);
$copy_arr = $arr;
testSort("selectSort", "selectSort", $arr, $n);
testSort("insertSortSeo", "insertSort", $copy_arr, $n);
複製代碼
結果對比dom
selectSort運行的時間爲:3.898992061615s
insertSort運行的時間爲:4.036700963974s
複製代碼
結果分析數據結構和算法
按常理來講,插入排序應該比選擇排序時間短,可是實際卻長,這主要是由於插入排序中頻繁進行swap操做形成的,而一次swap,須要進行三次交換,那麼有沒有優化的方法呢?有的!函數
/** * [insertSortSeo 優化的插入排序算法:swap是進行三次交換,將這三次交換改變成一次賦值] * @param [type] &$arr [description] * @param [type] $n [description] * @return [type] [description] */
function insertSortSeo(&$arr, $n){
for ($i=1; $i < $n; $i++) {
//採用複製的方式
$tmp = $arr[$i];
for ($j=$i; $j > 0 && $tmp < $arr[$j-1]; $j--) {
$arr[$j] = $arr[$j-1];
}
$arr[$j] = $tmp;
}
}
複製代碼
運行時間
//main
$n = 10000;
$arr = generateRandomArray($n, 0, $n);
// $arr = generateNearlyOrderedArray($n, 100);
$copy_arr = $arr;
testSort("selectSort", "selectSort", $arr, $n);
testSort("insertSortSeo", "insertSortSeo", $copy_arr, $n);
複製代碼
結果對比
selectSort運行的時間爲:4.1174781322479s
insertSortSeo運行的時間爲:1.817638874054s
複製代碼
插入排序在須要排序的數據基本有序的狀況下,很是快,甚至比O(n*logN)時間複雜度的算法還快,好比對服務器日誌記錄進行排序時, 日誌數據基本上都是有序的,只有少數任務執行時間較長,形成數據順序不一致,這中狀況下,很是適合插入排序算法。
測試比較
首先生成基本有序的數據:
/** * [generateNearlyOrderedArray 產生n個幾乎有序的數組, ] * @param [type] $n [description] * @param [type] $swapTimes [順序數組中調換的個數] * @return [type] [description] */
function generateNearlyOrderedArray($n, $swapTimes){
$arr = array();
for ($i=0; $i < $n; $i++) {
$arr[$i] = $i;
}
//調換數組
for ($i=0; $i < $swapTimes; $i++) {
$swap1 = rand(0, $n-1);
$swap2 = rand(0, $n-1);
swap($arr, $swap1, $swap2);
}
return $arr;
}
複製代碼
運行時間
//main
$n = 10000;
// $arr = generateRandomArray($n, 0, $n);
$arr = generateNearlyOrderedArray($n, 100);
$copy_arr = $arr;
testSort("selectSort", "selectSort", $arr, $n);
testSort("insertSortSeo", "insertSortSeo", $copy_arr, $n);
複製代碼
結果對比
selectSort運行的時間爲:2.0646297931671s
insertSortSeo運行的時間爲:0.040951013565063s
複製代碼
希爾排序算法就是插入算法的延伸。
-------------------------華麗的分割線--------------------
看完的朋友能夠點個喜歡/關注,您的支持是對我最大的鼓勵。
想了解更多,歡迎關注個人微信公衆號:番茄技術小棧