以前读刘未鹏的《暗时间》里面就有这样一个观点“互联网技术突飞猛进,程序员要学的技术变化的很快,但真正不变的东西其实不多,好比数据结构和算法”,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
复制代码
希尔排序算法就是插入算法的延伸。
-------------------------华丽的分割线--------------------
看完的朋友能够点个喜欢/关注,您的支持是对我最大的鼓励。
想了解更多,欢迎关注个人微信公众号:番茄技术小栈