徒手优化冒泡排序
冒泡排序是一种比较粗暴的基本排序,也是算法里面很常规的。今天我用php和js作为实现语言,一步一步去优化这个算法。常规的写法如下:
php部分:
1 <?php 2 /** 3 * 冒泡排序 4 * User:freephp 5 * Date: 2015/10/9 6 * Time: 14:09 7 */ 8 9 function bubbleSort($arr) { 10 if (empty($arr)) return false; 11 $len = count($arr); 12 13 for($i=0;$i<$len-1;$i++){ 14 for ($j=0; $j < $len-i-1; $j++) { 15 if($arr[$j+1] < $arr[$j]){ // 从小到大排序 16 $tmp=$arr[$j]; 17 $arr[$j]=$arr[$j+1]; 18 $arr[$j+1]=$tmp; 19 } 20 } 21 } 22 return $arr; 23 } 24 25 $arr1 = [33,23,54,1,4,7]; // php5的新写法 26 $newArr = bubbleSort($arr1); 27 print_r($newArr);
打印出来结果为:
Array
(
[0] => 1
[1] => 4
[2] => 23
[3] => 33
[4] => 54
)
js实现:
<script type="application/javascript"> function bubbleSort(arr) { var len = arr.length; if (len == 0 ) {console.log('不能为空数组!'); return false;} for (var i=0;i<len-1;i++) { for (var j=0;i<len-1-i;j++) { if (arr[j] > arr[j+1]) { var temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; } } } return arr; } var arr=[32,55,78,43,78,10,45,20,9,89]; bubbleSort(arr); for(var i=0;i<arr.length;i++){ document.write(arr[i]+","); } </script>
都是最原始的实现方式,双层循环一遍一遍去两两比较。时间复杂度为O(n*n).
做一下思考,如果在一趟排序中没有数据发生交换,那么就已经排好序了。我们只需要加个flag来做标识。
function bubbleSort2($arr) { if (empty($arr)) return false; $len = count($arr); for($i=0;$i<$len-1;$i++){ // 是否发生交换 $flag = false; for ($j=0; $j < $len-i-1; $j++) { if($arr[$j+1] < $arr[$j]){ // 从小到大排序 $tmp=$arr[$j]; $arr[$j]=$arr[$j+1]; $arr[$j+1]=$tmp; $flag = true; } } if (!$flag) return $arr; } return $arr; } $arr1 = [33,23,54,1,4,7,6]; // php5的新写法 $startTime = microtime(true); $newArr = bubbleSort($arr1); $endTime =microtime(true); $cost = $endTime - $startTime; print_r($newArr); echo "bubbleSort func cost time is:{$cost}\r\n"; $startTime = microtime(true); $newArr = bubbleSort2($arr1); $endTime =microtime(true); $cost = $endTime - $startTime; echo "bubbleSort2 func cost time is:{$cost}\r\n"; print_r($newArr);
打印出来如下结果:
Array
(
[0] => 1
[1] => 4
[2] => 6
[3] => 7
[4] => 23
[5] => 33
[6] => 54
)
bubbleSort func cost time is:0.000133037567139
bubbleSort2 func cost time is:0.000128984451294
Array
(
[0] => 1
[1] => 4
[2] => 6
[3] => 7
[4] => 23
[5] => 33
[6] => 54
)
可见改良后的bubbleSort2效率高得明显。同样js实现如下:
function bubbleSort2(arr) { var len = arr.length; if (len == 0 ) {console.log('不能为空数组!'); return false;} for (var i=0;i<len-1;i++) { var flag = false; // 每一趟外层比较的交换标记,默认是false for (var j=0;i<len-1-i;j++) { if (arr[j] > arr[j+1]) { var temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; flag = true; // 发生交换 } } if (!flag) return arr; } return arr; }
然而,我们既然都用了标识,那么更进一步在每次内循环比较的时候记录脚标,可以更加缩小比较范围。
顺便利用list函数巧妙交换数组,php实现如下:
function bubbleSortPro($arr) {
if (empty($arr)) return false;
$last = count($arr) - 1;
$num = $last + 1;
$lastCursor = 0;
for($i=0;$i < $last;$i++){
for ($j=0; $j < $last-$i; $j++) {
if($arr[$j+1] < $arr[$j]){ // 从小到大排序
list($arr[$j+1], $arr[$j]) = array($arr[$j], $arr[$j+1]);
$lastCursor = $j+1;
}
}
if ($lastCursor == $num) return $arr;
}
return $arr;
}
调用之后的结果为:
bubbleSortPro func cost time is:6.60419464111E-5
Array
(
[0] => 1
[1] => 4
[2] => 6
[3] => 7
[4] => 23
[5] => 33
[6] => 54
)
js原理一样,如下所示:
function bubbleSortPro(arr) { var len = arr.length; if (len == 0 ) {console.log('不能为空数组!'); return false;} var last = len -1; var lastCusor = 0; for (var i=0;i<last;i++) { for (var j=0;i<last-i;j++) { if (arr[j] > arr[j+1]) { var temp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = temp; lastCusor = j+1; } } if (lastCusor == len) return arr; } return arr; }
总结:缩小循环和判断游标范围,人为优化算法是关键。