常见排序算法(php)

冒泡法:

这个最简单了:

function bubble_sort($arr)
{
    $n = count($arr);
    for($i=0;$i<$n;$i++){
        $flag = 1; //1
        for($j=0;$j<$n-$i-1;$j++){
            if($arr[$j] > $arr[$j+1]){
                $flag = 0; //2
                $tmp       = $arr[$j+1];
                $arr[$j+1] = $arr[$j];
                $arr[$j]   = $tmp;
            }
        }
        if($flag) {
            return $arr; //3
        } 
    }
    return $arr;
}

其中1,2,3处不是必须的,加入这个检查是因为如果某一趟冒泡中一次也没有交换发生,说明整个数组已经是有序的了。

插入排序

这个也比较简单,每次处理就是将无序数列的第一个元素与有序数列的元素从后往前逐个进行比较,找出插入位置。

假设前半部分从1 ~ n -1是有序的,那么将第n项的值保存到一个临时变量t,用这个变量与n-1比较;

如果n-1项大于t,将第n-1项移到第n项,再比较第n-2项,如果大于t移到第n-1项.........直到找到一个数(假设位置为k)小于t,将t插到这个数前面也就是K+1处。

如果n-1项小于t,那么说明1 ~ n-1项都小于n项,1 ~ n 也都是有序的。

n++ ,重复这个过程,一直到最后n为数组最后一项。

function insert_sort($arr)
{
	$n = count($arr);
	for($i=1;$i<$n;$i++){
		$tmp = $arr[$i]; // 要插入的值
		$j = $i-1;
		while($j>=0){  
			if($arr[$j]>$tmp){
				$arr[$j+1] = $arr[$j];//比要插入的值大往后移
			} else {
				break; // 比要插入的值小或相等 它前面也就是 $j+1处就是要插入的位置
			}
			$j--;
		}
		if($j<$i-1 ){ // 如果 $j == $i-1 说明前面都小于要插入的值,当然没有这个判断效果也一样
			$arr[$j+1] = $tmp;
		}
	}
	return $arr;
}



选择排序

每次都选择后面最小的项和当前项交换

function select_sort($arr)
{
	$n = count($arr);
	for($i=0;$i<$n;$i++){
           // 最小元素的值和键
           $min = $arr[$i];
		$key = $i;
		for($j=$i+1;$j<$n;$j++){
			if($arr[$j] < $min){
				$min = $arr[$j];
				$key = $j;
			}
		}
              // 找到最小项后跟当前项交换
               if($key != $i){
			$tmp       = $arr[$i];
			$arr[$i]   = $arr[$key];
			$arr[$key] = $tmp;
		}
	}
	return $arr;
}



快速排序


首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,然后对前面和后面两个部分递归的进行这个过程。

每一趟的实现 把所有比关键数据小的数都放到它前面,所有比关键数据大的数都放到它后面这个效果的过程为

1.一开始操作范围为第一个到最后一个元素,选取第一个作为关键数据,从后往前找到第一个比关键数小的数与之交换。这个位置记为 K。

2.现在关键数的位置变到k了,比较的方向也要改变,操作的范围也从第二个到第K个了(因为k后面都是比关键数大的数了);

然后从第二个开始往后面找到第一个比关键数大的数与k这个位置的关键数交换。这个位置记为 K2。

3.现在关键数的位置又变了到K2了(K2前面的都是比关键数小的),操作的范围也从K2到第K-1个了,然后又回到第一步,直到操作范围为0,;


至此终于实现比关键数据小的数都在他前面,比关键数据大的数都在它后面这个效果了,然后对前面和后面两个部分递归的进行这个过程就可以得到有序的数组了。


程序如下:


function recu_fast_sort(&$arr,$start,$end)
{
	 
	$left  = $i = $start; // $i记录关键数的位置
	$right = $end;
	$flag  = 0; // 记录比较的方向
	while($start < $end){
		if($flag == 0 ){
			if($arr[$i] > $arr[$end]){ // 找到一个比关键数小的数 交换
				$tmp       = $arr[$i];
				$arr[$i]   = $arr[$end];
				$arr[$end] = $tmp;
				$i = $end;  // 新的关键数位置
				$flag = 1;  // 比较的方向改变
			} else {
				$end--;
			}
		} else {
			if($arr[$i] < $arr[$start]){    // 找到一个比关键数大的数 交换
				$tmp         = $arr[$i];
				$arr[$i]     = $arr[$start];
				$arr[$start] = $tmp;
				$i = $start;
				$flag = 0;
			} else {
				$start++;
			}
		}
	}
	if($left < $i-1){  // 递归前面一部分
		recu_fast_sort($arr,$left,$i-1);
	}
	if($right > $i+1){ // 递归后面一部分
		recu_fast_sort($arr,$i+1,$right);
	}
}

// 上面是递归版本的下面是不递归的版本的,要把递归的改成不递归的,就用一个数组模拟一个队列,把原来要递归的操作区域放到数组中

function fast_sort($arr)
{
	$n = count($arr);
	//要操作的区域放入数组
	$arr_que = array(array(0,$n-1));
	while(!empty($arr_que)){
		// 取数组的第一项作为操作区域
		$q = current($arr_que);
		// 删除这一项
		array_shift($arr_que);
		$left  = $i = $q[0];
		$right = $q[1];
		$flag = 0;
		while($left < $right){
			if($flag == 0 ){
				if($arr[$i] > $arr[$right]){
					$tmp         = $arr[$i];
					$arr[$i]    = $arr[$right];
					$arr[$right] = $tmp;
					$i = $right;
					$flag = 1;
				} else {
					$right--;
				}
			} else {
				if($arr[$i] < $arr[$left]){
					$tmp         = $arr[$i];
					$arr[$i]    = $arr[$left];
					$arr[$left] = $tmp;
					$i = $left;
					$flag = 0;
				} else {
					$left++;
				}
			}
		}
		// 把新的操作区域添加到数组末尾
		if($q[0] < $i-1){
			array_push($arr_que,array($q[0],$i-1));
		}
		if($q[1]> $i+1){
			array_push($arr_que,array($i+1,$q[1]));
		}

	}
        return $arr;
 }

归并排序法(2路归并)

归并操作:

假设两个数组都是有序的,那么要把这两个数组合并成一个有序的数组,依次选取两个数组中最小的项添加到新数组即可,因为两个数组都是有序的

所以选取最小的从前往后选就可以了。

由于数组中的每一项都可以看做是只有一项的子数组,所以一开始每2项之间可以合并,然后再每4项,一直到整个数组只剩下两个部分合并。

// 归并函数:
function merger_arr(&$arr,$start,$mid,$last)
{
	// 初始化两个数组分别存放要归并的两个部分
        $arr1 = array();
	$arr2 = array();
	for($i=$start;$i<=$last;$i++){
		if($i<=$mid){
			$arr1[] = $arr[$i];
		}else{
			$arr2[] = $arr[$i];
		}
	}


	$i=0;$j=0;
	$k = $start;
        //两个部分元素的个数
        $n1 = $mid-$start +1;
	$n2 = $last-$mid;
        // 合并两个临时数组到原来的数组
        while($i< $n1|| $j<$n2){
		if($i == $n1){
			$arr[$k] = $arr2[$j];
			$j++;
		} else if($j == $n2){
			$arr[$k] = $arr1[$i];
			$i++;
		} else if($arr1[$i] < $arr2[$j]){
			$arr[$k] = $arr1[$i];
			$i++;
		} else {
			$arr[$k] = $arr2[$j];
			$j++;
		}
		$k++;
	}
}

// 归并排序
function merger_sort($arr)
{
    $n = count($arr);
    $step = 2;// 每次归并的项数
    while($step < $n*2){  // 后面一部分不一定有$step/2个元素,有可能小于$step/2,这样最后一步$step/2一般会大于$n/2
        for($i=0;$i<$n;$i=$i+$step){
            $end = $i+$step > $n ? $n-1:$i+$step-1;
            $mid = $i+$step/2-1;
            if($mid < $end ){
                // 归并两个部分
                merger_arr($arr,$i,$mid,$end);
            }
        }
        $step *=2;
    }
    return $arr;
}




//上面是不递归的是从最小的项开始合并的,其实这个算法用递归写更简单,但是理解起来有点不直观。

如下:

// 归并排序
function merger_sort(&$arr,$start,$end)
{
    if($start < $end){
        // 把数组分为两个部分
        $i = intval(($start+$end)/2);
        // 对两个部分分别进行归并排序
        merger_sort($arr,$start,$i);
        merger_sort($arr,$i+1,$end);
        // 归并两个部分  
        merger_arr($arr,$start,$i,$end);
    }
}



另外附二分法查找

二分法查找的前提是数组已经排好序了

function binary_search($arr,$value)
{
	$n = count($arr);
	if($arr[0] == $value){
		return 0;
	}
	if($arr[$n-1] == $value){
		return $n-1;
	}
	$left = 0;
	$right = $n-1;
        //要注意的是边界,这里每次循环中 $arr[$left] 和$arr[$right]都是不可能等于$value的
        while($left < $right){
		$mid = intval(($left + $right)/2);
		if($arr[$mid] == $value){
			return $mid;
		} else if($arr[$mid] > $value){
			$right = $mid;
		} else {
			$left = $mid;
		}
	}
	return -1;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值