php实现冒泡排序

冒泡排序很简单,就是不断地交换相邻的数,使得最大的数排在最后面,即一次循环可以确定最大一个数的排序位置。
php代码实现:

function bubble(&$arr){
    for($i = 1; $i < count($arr); $i++){//第n次循环可以确定后n个的位置
        for($j = 0; $j < count($arr)-$i; $j++){//确定的位置就不用再遍历了
            if($arr[$j] > $arr[$j+1]){
                swap($arr[$j],$arr[$j+1]);
            }
        }
    }
}

关于上面的swap函数,做一下备注:
swap很多人用异或来实现,如下:

function swap(&$a,&$b){
    $a ^= $b;
    $b ^= $a; 
    $a ^= $b;
}

但是这种方法有个缺陷,就是当两个参数都指向一个变量地址时,异或得到结果是0.
所以还是推荐用以下的方法:

function swap(&$a,&$b){
    $tmp = $a;
    $a = $b;
    $b = $tmp;
}

若是非要用异或来实现,就加个限制条件:

function swap(&$a,&$b){
    if($a != $b){
        $a ^= $b;
        $b ^= $a; 
        $a ^= $b;
    }
}



再说一说上面的冒泡的缺陷:
如果有如下的数组array(4,3,2,1,5,6,7,8,9);,那么冒泡的每一步如下:

第1步: 3 2 1 4 5 6 7 8 9 
第2步: 2 1 3 4 5 6 7 8 9 
第3步: 1 2 3 4 5 6 7 8 9 
第4步: 1 2 3 4 5 6 7 8 9 
第5步: 1 2 3 4 5 6 7 8 9 
第6步: 1 2 3 4 5 6 7 8 9 
第7步: 1 2 3 4 5 6 7 8 9 
第8步: 1 2 3 4 5 6 7 8 9 

发现了没有,当到第三步时,排序已经完成,但是冒泡排序还在做无用功。
所以,改进以下冒泡排序算法:设置一个标志变量,如果第n步的内部循环未发生交换,则证明排序已经完成:

function bubble(&$arr){
    $flag;
    for($i = 1; $i < count($arr); $i++){
        $flag = false;
        for($j = 0; $j < count($arr)-$i; $j++){
            if($arr[$j] > $arr[$j+1]){
                swap($arr[$j],$arr[$j+1]);
                $flag = true;
            }
        }
        if(!$flag){break;}
    }
}

输出一下遍历顺序:

第1步: 3 2 1 4 5 6 7 8 9 
第2步: 2 1 3 4 5 6 7 8 9 
第3步: 1 2 3 4 5 6 7 8 9 

还可以进一步改进,可以发现,仅前面4个是无序的,后5个都是有序,且都大于前面的数。那么在第一趟遍历后,最后发生交换的位置必定小于4,且这个位置之后的数据必定已经有序了,记录下这位置,第二次只要从数组头部遍历到这个位置就可以了。

function bubble(&$arr){
    $pos = count($arr)-1;//第pos下标后面的数已经排好序了
    while($pos > 0){
        $k = $pos;
        $pos = 0;//准备找下一趟遍历的pos下标
        for($j = 0; $j < $k; $j++){
            if($arr[$j] > $arr[$j+1]){
                swap($arr[$j],$arr[$j+1]);
                $pos = $j+1;
            }
        }
    }
}

冒泡排序毕竟是一种效率低下的排序方法,在数据规模很小时,可以采用。数据规模比较大时,最好用其它排序方法。


参考资料:
白话经典算法系列之一 冒泡排序的三种实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值