分析与解答:
冒泡排序,顾名思义就是整个过程就像气泡一样往上升,单向冒泡排序的基本思想是(假设由小到大排序):对于给定的 n 个记录,从第一个记录开始依次对相邻的两个记录进行比较,当前面的记录大于后面的记录时,交换其位置,进行一轮比较和换位后,n 个记录中的最大记录将位于第 n 位;然后对前(n-1)个记录进行第二轮比较;重复该过程直到进行比较的记录只剩下一个时为止。算法原理如下:
1)比较相邻的元素,如果第一个比第二个大,那么就交换这两个元素。
2)对每一对相邻元素做同样的工作,从第一对开始到最后一对结束,最后的元素应该会是最大的数。
3)除了最后一个元素外,针对其他的元素重复以上的步骤。
4)对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较为止。
以数组 array(36, 25, 48, 12, 25, 65, 43, 57)为例,具体排序过程如下:
初始状态:[36 25 48 12 25 65 43 57]
1 趟排序:[25 36 12 25 48 43 57] 65]
2 趟排序:[25 12 25 36 43 48] 57 65]
3 趟排序:[12 25 25 36 43] 48 57 65]
4 趟排序:[12 25 25 36] 43 48 57 65]
5 趟排序:[12 25 25] 36 43 48 57 65]
6 趟排序:[12 25] 25 36 43 48 57 65]
7 趟排序:[12] 25 25 36 43 48 57 65]
根据以上的实现原理,实现代码如下:
<?php
function maopao($arr){
$len = count($arr);
for($i = 1; $i < $len;$i++){
for($k = 0; $k < $len; $k++){
if($arr[$k] > $arr[$k+1]){
$tmp = $arr[$k+1];
$arr[$k+1] = $arr[$k];
$arr[$k] = $tmp;
}
}
}
return $arr;
}
$arr = [36,25,48,12,25,65,43,57];
echo "排序前";
foreach ($arr as $k => $val){
echo $val.' ';
}
echo "\n排序后";
$arr = maopao($arr);
foreach ($arr as $k => $val){
echo $val.' ';
}
程序的运行结果为
排序前36 25 48 12 25 65 43 57
排序后12 25 25 36 43 48 57 65
在传统的冒泡排序基础上,可以进一步改进冒泡排序算法,通过设置一个标志 bool,用于记录每趟排序中最后一次交换的位置。由于 bool 标志之后的记录均已交换到位,因此下一趟排序时只要扫描到 bool 位置即可,不需要再对 bool 后的循环排序。改进后的冒泡排序算法 2 如下:
<?php
function maopao($arr){
$i = count($arr) - 1; //初始时,最后位置保持不变
while ($i > 0){
$bool = 0;
for($j = 0; $j < $i; $j++){
if($arr[$j] > $arr[$j+1]){
$bool = $j; //记录交换的位置
$tmp = $arr[$j];
$arr[$j] = $arr[$j+1];
$arr[$j+1] = $tmp;
}
}
$i = $bool; //为下一趟排序做准备
}
return $arr;
}
$arr = [36,25,48,12,25,65,43,57];
echo "排序前";
foreach ($arr as $k => $val){
echo $val.' ';
}
echo "\n排序后";
$arr = maopao($arr);
foreach ($arr as $k => $val){
echo $val.' ';
}
程序的运行结果为
排序前36 25 48 12 25 65 43 57
排序后12 25 25 36 43 48 57 65
因为传统冒泡排序中每一趟排序操作只能找到一个最大值或最小值,所以可以考虑在每趟排序中进行正向和反向两遍冒泡的方法,一次得到最大者和最小者,从而可使排序趟数将近减少一半。再次改进后的冒泡排序法 3 如下:
<?php
function maopao($arr){
$low = 0;
$high = count($arr) - 1;
while($low < $high){
for($j = $low; $j<$high;++$j){
if($arr[$j] > $arr[$j+1]){
$tmp = $arr[$j];
$arr[$j] = $arr[$j+1];
$arr[$j+1] = $tmp;
}
}
--$high;
for($j = $high; $j < $low; --$j){
if($arr[$j]< $arr[$j-1]){
$tmp = $arr[$j];
$arr[$j] = $arr[$j-1];
$arr[$j-1] = $tmp;
}
}
++$low;
}
return $arr;
}
$arr = [36,25,48,12,25,65,43,57];
echo "排序前";
foreach ($arr as $k => $val){
echo $val.' ';
}
echo "\n排序后";
$arr = maopao($arr);
foreach ($arr as $k => $val){
echo $val.' ';
}
程序的运行结果为
```shell
排序前36 25 48 12 25 65 43 57
排序后12 25 25 36 43 48 57 65
以上介绍的冒泡排序法中,它们执行的效率:
传统冒泡排序法 < 改进后冒泡排序法 2< 改进后冒泡排序法 3。
算法性能分析:
最佳情况:T(n)=O(n),当输入的数据为正序时,则是最佳情况。
最差情况:T(n)=O(n2),当输入的数据是反序时,则是最差情况,需依次从头到尾重新排序。
平均情况:T(n)=O(n2)。