由于对这些算法的概念比较抵触,很难理解痛彻。但是我对代码还是很上手的,通过看代码,我就能清晰明了的知道原理和思想。
1、归并排序:
下面代码可以直接运行。摘抄自:常用的排序算法(四)--归并排序(PHP实现)。其中原文中,理论部分讲解有问题。
思路:分治思想。选取中间值,进行分隔。分为左边数组和右边数组。递归的调用该方法,目的在于一直分隔数组,直到当前数组只有一个元素为止。时间复杂度 nlogn。每次递归时间复杂度为logn,调用n次。
$ar = [3,2,7,1,4,5];
echo "input: <br/>";
print_r(json_encode($ar));
echo "<br/>";
echo "<br/>";
$ar = merge_func($ar);
echo "result: <br/>";
print_r(json_encode($ar));
echo "<br/>";
echo "<br/>";
/** 归并排序 先拆左右 在两两合并
* @param array $ar
* @param null $len
* @return array
*/
function merge_func(array $ar, $len = null)
{
if ($len === null) {
$len = sizeof($ar);
}
if ($len <= 1) {//len = 1 finish cuting
return $ar;
}
//len>1 --> need sort and merge left and right
//cut into 2 part -- left and right
$mid = $mid = intval($len / 2);
// 0 - mid xxxxx
$left = array_slice($ar, 0, $mid);
// xxxx mid - end
$right = array_slice($ar, $mid);
echo "left:";
print_r(json_encode($left));
echo " -- right:";
print_r(json_encode($right));
echo "<br/>";
$left = merge($left);//continue cut into 2 part until len = 1
$right = merge($right);
//get the smallest sorted unit to merge (len is decided by last function result)
$merge = [];
$len_left = sizeof($left);
$len_right = sizeof($right);
//init index, i for left ,j for right
$i = $j = 0;
//put left and right into merge by sorting
while (sizeof($merge) < $len_left + $len_right) {
if ($i < $len_left //still has left
&& ($j == $len_right || $left[$i] <= $right[$j])) { //right is over or left is smaller --> add left into merge
$merge[] = $left[$i];
$i++;
} else if ($j < $len_right //still has right
&& ($i == $len_left || $left[$i] > $right[$j])) {//left is over or right is smaller --> add left into merge
$merge[] = $right[$j];
$j++;
}
}
echo " merge:";
print_r(json_encode($merge));
echo "<br/>";
return $merge;
}
2、快速排序
--思想:选取一个基准数,然后遍历数组,比这个基准数大的,放右边数组;比这个基准数小的,放左边。递归调用,不断分隔,到左右数组中的仅有一个数据时,返回。最后,合并左右数组,完成。
参考文章:PHP 实现快速排序
$arr = [2,1,4,3,7];
function quickSort($arr)
{
$count = count($arr);
if ($count < 2) {
return $arr;
}
$leftArray = $rightArray = array();
$middle = $arr[0];// 基准值
for ($i = 1; $i < $count; $i++) {
// 小于基准值,存入左边;大于基准值,存入右边
if ($arr[$i] < $middle) {
$leftArray[] = $arr[$i];
} else {
$rightArray[] = $arr[$i];
}
}
$leftArray = quickSort($leftArray);
$rightArray = quickSort($rightArray);
return array_merge($leftArray, array($middle), $rightArray);
// 倒序
// return array_merge($rightArray, array($middle), $leftArray);
}
print_r(quickSort($arr));
3、选择排序
--思想:选取一个基准值(一般选择数组第一个值),然后通过遍历数组找到一个比这个基准值小的值的下标,用这个值覆盖基准值,依次往后遍历,基准值也往后移动。时间复杂度:O(n2)
$arr = [49,38,65,97,76,13,27,49];
//$arr = [8,6,9,4,3];
function choseSort($arr)
{
$size = count($arr);
for($i = 1; $i< $size-1; $i++) {
$min = $i;
for($j = $i+1; $j<$size; $j++) {
if ($arr[$j] < $arr[$min]) {
$min = $j;
} else {
continue;
}
}
$tmp = $arr[$i-1];
$arr[$i-1] = $arr[$min];
$arr[$min] = $tmp;
}
return $arr;
}
$arr = choseSort($arr);
print_r($arr);
4、插入排序
--思想:将比前一个数小的数,插入到一个已经排好序的数组中。默认数组中第一个数是已经排好序的。所以遍历是从第二个数开始的。时间复杂度:o(n2)
$arr = [2,1,5,3,6,4,9,8,7];
function insertSort($arr)
{
$size = count($arr);
for($i = 1; $i< $size; $i++) {
$base = $arr[$i];
for($j = $i-1; $j>= 0;$j--) {
if ($arr[$j] > $base) {
$arr[$j+1] = $arr[$j];
} else {
break;
}
}
$arr[$j+1] = $base;
}
return $arr;
}
$arr = insertSort($arr);
print_r($arr);
5、冒泡排序
--思想:两次遍历,每次都是前后数进行比较,前面数大于后面数,进行位置交换。优化点:设置一个flag。当已经是一个排序好的数组时,跳出循环。
function bubble(array & $ar, $len = null)
{
if ($len === null) {
$len = sizeof($ar);
}
for ($i = 0; $i < $len-1; $i++) {
for ($j = 0; $j < $len-$i-1; $j++) {
if ($ar[$j] > $ar[$j+1]) {//swap
$t = $ar[$j];
$ar[$j] = $ar[$j+1];
$ar[$j+1] = $t;
}
}
print_r(json_encode($ar));
echo "<br/>";
}
}
8、桶排序
网上很多关于桶排序的代码都有问题,理论知识没有问题。大家在阅读时,一定要理解着。参考文章:菜鸟教程--桶排序
--思想:把数据按照某种映射关系,分别分配到不同的桶中,然后对每个桶进行上面任何一种排序(快速排序),最后合并即为有序数据。
主要是利用二维数组arr[x][y]。其中一维下标x即表示每个桶,y表示对应桶中包含的被分配的数据。对桶进行排序即给y中的数据进行排序。最后,遍历二维数组,合并成一维数组,完成排序。
其中,最主要的是需要多少个桶来装下这些数据呢?假设一个桶中只放一条数据(这样效率最高(可以省去对桶进行排序的时间)),那么怎么计算需要多少个桶呢?
桶个数 = (最大数值 - 最小数值)/ 桶的大小 + 1
那么,我们一开始就要统计出最大数值和最小数值,并跟据桶的个数初始化每个桶。对了,这个映射关系怎么确定呢?
桶的位置 = (每个数据 - 最小数值)/ 桶的大小 注:向下取整
具体代码代码入下:
function bucketSort($arr, $bucketSize = 1)
{
if (count($arr) === 0) {
return $arr;
}
$minValue = $arr[0];
$maxValue = $arr[0];
for ($i = 1; $i < count($arr); $i++) {
if ($arr[$i] < $minValue) {
$minValue = $arr[$i];
} else if ($arr[$i] > $maxValue) {
$maxValue = $arr[$i];
}
}
$bucketCount = floor(($maxValue - $minValue) / $bucketSize) + 1;
$buckets = array();
for ($i = 0; $i < $bucketCount; $i++) {
$buckets[$i] = [];
}
// var_dump($buckets);
for ($i = 0; $i < count($arr); $i++) {
$buckets[floor(($arr[$i] - $minValue) / $bucketSize)][] = $arr[$i];
}
var_dump($buckets);
echo count($buckets);
$arr = array();
for ($i = 0; $i < count($buckets); $i++) {
$bucketTmp = $buckets[$i];
sort($bucketTmp);
for ($j = 0; $j < count($bucketTmp); $j++) {
$arr[] = $bucketTmp[$j];
}
}
return $arr;
}
$arr = array(5,1,4,3,7);
// array(29,25,3,49,9,37,21,43);
// $arr = array(49,38,65,97,76,13,27,49,55,4);
$arr = bucketSort($arr, 1);
var_dump($arr);
9、堆排序
由于属于二叉树部分,暂时还未更新。
更新:
堆满足二个特性:
- 父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
- 每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。下图展示一个最小堆:

有关堆的插入,删除,堆的复原,堆的排序请转---》白话经典算法系列之七 堆与堆排序
上面的代码,后面再补充。

3658

被折叠的 条评论
为什么被折叠?



