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