徒手优化冒泡排序

冒泡排序是一种比较粗暴的基本排序,也是算法里面很常规的。今天我用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;
    }

总结:缩小循环和判断游标范围,人为优化算法是关键。

posted @ 2015-10-09 15:02  freephp  阅读(369)  评论(1编辑  收藏  举报