几种常见的排序算法之PHP代码简释

写在前面:本文侧重诠释对算法的思考记录过程,忽略其他诸如代码简洁、字符编码等细节问题。

<?php
//冒泡排序:冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,
//看是否满足大小关系要求,如果不满足就让它俩互换。一次冒泡会让至少一个元素移动到它应该在的位置,重复 n 次,
//就完成了 n 个数据的排序工作。
//时间复杂度: O(n*n)
function bubble_sort($arr) {
	if (count($arr) <= 1 ) {
		return $arr;
	}

	for ($i=0; $i<count($arr); $i++) {
		$flag = false;
		for ($j=0; $j<count($arr)-1-$i; $j++) {
			if ($arr[$j] > $arr[$j+1]) {
				$temp = $arr[$j+1];
				$arr[$j+1] = $arr[$j];
				$arr[$j] = $temp;
				$flag = true;
			}
		}
		//当某一次遍历的时候发现没有需要交换的元素时,则认为整个序列已经排序完成
		if (!$flag) {
			break;
		}
	}

	return $arr;
}

//插入排序的原理是:数据分为两个区间,已排序区间和未排序区间。核心思想是取未排序区间中的元素,
//在已排序区间中找到合适的插入位置将其插入,并保证已排序区间数据一直有序。重复这个过程,
//直到未排序区间中元素为空,算法结束。
//时间复杂度:O(n*n)
function insert_sort($arr) {
	if (count($arr) <= 1) {
		return $arr;
	}

	for ($i=0; $i<count($arr); $i++) {
		$value = $arr[$i];
		$j=$i-1;
		for (; $j>=0; $j--) {
			if ($arr[$j] > $value) {
				$arr[$j+1] = $arr[$j];
			} else {
				break;
			}
		}
		$arr[$j+1] = $value;
	}
	return $arr;
}

//选择排序,也分已排序区间和未排序区间。但是选择排序每次会从未排序区间中找到最小的元素,
//将其放到已排序区间的末尾。重复这个过程,直到未排序区间中元素为空,算法结束。
//时间复杂度: O(n*n)
function select_sort($arr) {
	if (count($arr) <= 1) {
		return $arr;
	}

	for ($i=0; $i<count($arr); $i++) {
		$min = $i;
		for ($j=$i+1; $j<count($arr); $j++) {
			if ($arr[$j] < $arr[$min]) {
				$min = $j;
			}
		}
		$temp = $arr[$i];
		$arr[$i] = $arr[$min];
		$arr[$min] = $temp;
	}
	return $arr;
}

//归并排序:采用了分治法,从字面意思理解,就是先递归分割给定的一组数据,
//直到不能再往下分割为止,这样排序后再合并起来即可。
//时间复杂度:
//T(n) = 2*T(n/2) + n
//     = 2*(2*T(n/4) + n/2) + n  = 4*T(n/4) + 2*n
//     = 4(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n
//     = ....................... = 2^k*T(n/2^k) + k*n 注:n/2^k≈1,n≈2^k,k=log2n,2为底
//     = n*T(1) + n*(log2n)      = n(C + log2n) 注:常量忽略不计,忽略低阶
//     = nlogn
function separate_merge_sort($arr) {
	if (count($arr) <= 1) {
		return $arr;
	}

	separate_merge($arr, 0, count($arr)-1);
	return $arr;
}
function separate_merge(&$arr, $l, $r) {
	if ($l >= $r) {
		return;
	}

	$m = floor(($l + $r) / 2);
	separate_merge($arr, $l, $m);
	separate_merge($arr, $m+1, $r);

	merge($arr, ['start'=>$l,'end'=>$m],['start'=>$m+1,'end'=>$r]);
}
function merge(&$arr, $lrr, $rrr) {
	$s1 = $lrr['start'];
	$s2 = $rrr['start'];
	$temp = [];
	$k = 0;
	while ($s1<=$lrr['end'] && $s2<=$rrr['end']) {
		if ($arr[$s1] <= $arr[$s2]) {
			$temp[$k++] = $arr[$s1++];
		} else {
			$temp[$k++] = $arr[$s2++];
		}
	}
	if ($s1 <= $lrr['end']) {
		for (; $s1<=$lrr['end']; $s1++) {
			$temp[$k++] = $arr[$s1];
		}
	}
	if ($s2 <= $rrr['end']) {
		for (; $s2<=$rrr['end']; $s2++) {
			$temp[$k++] = $arr[$s2];
		}
	}
	for ($i=0; $i<$k; $i++) {
		$arr[$lrr['start']+$i] = $temp[$i];
	}
}

//快速排序:取插入排序和归并排序两者的优点,先找到一个分区点 pivot,比pivot小的放到左侧区间,
//比pivot大的放到右侧区间,pivot放在中间,重复这个过程至无法再分区为止。
//时间复杂度:O(nlogn)
function quik_partition_sort($nums) {
	if (count($nums) <= 1) {
		return $nums;
	}
	
	quik_partition($nums, 0, count($nums)-1);
	return $nums;
}
function quik_partition(&$nums, $start, $end) {
	if ($start >= $end) {
		return;
	}

	$middle = partition($nums, $start, $end);
	quik_partition($nums, $start, $middle-1);
	quik_partition($nums, $middle+1, $end);
}
function partition(&$nums, $s ,$e) {
	$pivot = $nums[$e];
	$i = $s;

	for ($j=$s; $j<$e; $j++) {
		if ($nums[$j] < $pivot) {
			$temp = $nums[$i];
			$nums[$i] = $nums[$j];
			$nums[$j] = $temp;
			$i++;
		}
	}

	$temp = $nums[$i];
	$nums[$i] = $pivot;
	$nums[$e] = $temp;
	return $i;
}

参考来源:https://xueyuanjun.com/books/data-structure-and-algorithms

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值