<?php
//从时间上来看,快速排序和归并排序在时间上比较有优势,
//但是也比不上sort排序,归并排序比较占用内存!
$arr = [4,6,1,2,3,89,56,34,56,23,65];
/**
* 冒泡排序
* 它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。
* 走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成
*/
function BubbleSortq($arr)
{
$len = count($arr);
//设置一个空数组 用来接收冒出来的泡
for ($i = 1; $i < $len; $i++) //该层循环控制 需要冒泡的轮数
{
$flag = false; //本趟排序开始前,交换标志应为假
//该层循环用来控制每轮 冒出一个数 需要比较的次数
for ($k = 0; $k < $len - $i - 1; $k++)
{
//从小到大排序
if ($arr[$k] > $arr[$k + 1])
{
$tmp = $arr[$k + 1];
$arr[$k + 1] = $arr[$k];
$arr[$k] = $tmp;
$flag = true;
}
}
if(!$flag) return $arr;
}
}
// print_r(BubbleSort($arr));
/**
* 选择排序算法
* 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。
* 选择排序是不稳定的排序方法(比如序列[5, 5, 3]第一次就将第一个[5]与[3]交换,导致第一个5挪动到第二个5后面)
*/
function SelectSort($arr)
{
//定义进行交换的变量
$temp = 0;
for ($i = 0; $i < count($arr) - 1; $i++)
{
$minval = $arr[$i];//假设$minval就是最小的值
$minvalIndex = $i;//最小值的下标
for ($j = $i + 1; $j < count($arr); $j++)
{
if ($minval > $arr[$j])//从小到大排列
{
$minval = $arr[$j];//找最小值
$minvalIndex = $j;
}
}
$temp = $arr[$i];
$arr[$i] = $arr[$minvalIndex];
$arr[$minvalIndex] = $temp;
}
return $arr;
}
// print_r(SelectSort($arr));
/**
* 插入算法
* 每步将一个待排序的纪录,按其关键码值的大小插入前面已经排序的文件中适当位置上,直到全部插入完为止。
* 算法适用于少量数据的排序,时间复杂度为O(n^2)。是稳定的排序方法。
*/
function insertSort($arr)//从小到大排列
{
//先默认$arr[0],已经有序,是有序表
for ($i = 1; $i < count($arr); $i++)
{
$insertval = $arr[$i];//$insertval是准备插入的数
$insertIndex = $i - 1;//有序表中准备比较的数下标
while ($insertIndex >= 0 && $insertval < $arr[$insertIndex])
{
$arr[$insertIndex + 1] = $arr[$insertIndex];//将数组往后挪
$insertIndex--;//将下标往前挪,准备与前一个进行比较
}
if ($insertIndex + 1 !== $i)
{
$arr[$insertIndex + 1] = $insertval;
}
}
return $arr;
}
// print_r(insertSort($arr));
/*
* 快速排序法
* 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
* 然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
*/
function quickSort($arr)
{
//判断是否为数组
if (is_array($arr))
{
return false;
}
//如果数组长度为1直接返回
if (!isset($arr[1]))
{
return $arr;
}
$mid = $arr[0]; //获取一个用于分割的关键字,一般是首个元素
$leftArray = array();
$rightArray = array();
foreach ($arr as $v)
{
if ($v > $mid)
{
$rightArray[] = $v; //把比$mid大的数放到一个数组里
}
if($v < $mid)
{
$leftArray[] = $v; //把比$mid小的数放到另一个数组里
}
}
$leftArray = quickSort($leftArray); //把比较小的数组再一次进行分割
$leftArray[] = $mid; //把分割的元素加到小的数组后面,不能忘了它哦
$rightArray = quickSort($rightArray); //把比较大的数组再一次进行分割
return array_merge($leftArray,$rightArray); //组合两个结果
}
// print_r(quickSort($arr));
/**
* 归并排序
* 归并排序是指将两个或两个以上有序的数列(或有序表),合并成一个仍然有序的数列(或有序表)。
* 这样的排序方法经常用于多个有序的数据文件归并成一个有序的数据文件。
*/
function mergeSort(&$arr)
{
$len = count($arr);//求出数组长度
mSort($arr,0,$len - 1);
return $arr;
}
//实际实现归并排序的程序
function mSort(&$arr,$left,$right)
{
if ($left < $right)
{
//说明子序列内存在多余1个的元素,那么需要拆分,分别排序,
//合并计算拆分的位置,长度/2 取整
$center = floor(($left + $right) / 2);
//递归调用对左边进行再次排序
mSort($arr, $left, $center);
//递归调用对右边进行再次排序
mSort($arr, $center + 1, $right);
//合并排序结果
mergeArray($arr, $left, $center, $right);
}
}
//讲两个有序数组合并成一个有序数组
function mergeArray(&$arr, $left, $center, $right)
{
//设置两个起始位置标记
$a_i = $left;
$b_i = $center + 1;
while ($a_i <= $center && $b_i <= $right)
{
//当数组A和数组B都没有越界时
if ($arr[$a_i] < $arr[$b_i])
{
$temp[] = $arr[$a_i++];
}
else
{
$temp[] = $arr[$b_i++];
}
}
//判断 数组A内的元素是否都用完了,没有的话将其全部插入到C数组内
while ($a_i <= $center)
{
$temp[] = $arr[$a_i++];
}
//判断 数组A内的元素是否都用完了,没有的话将其全部插入到C数组内
while ($b_i <= $right)
{
$temp[] = $arr[$b_i++];
}
//将$arrC内排序好的部分,写入到$arr内
for ($i = 0, $len = count($temp); $i < $len; $i++)
{
$arr[$left + $i] = $temp[$i];
}
}
// print_r(mergeSort($arr));
/*
* 希尔排序
* 将数组按指定步长分隔成若干子序列,然后分别对子序列进行排序(在这是直接)
*/
function shellSort($arr)
{
$len = count($arr);
$k = floor($len / 2);
while ($k > 0)
{
for ($i = 0; $i < $k; $i++)
{
for ($j = $i; $j < $len, ($j + $k) < $len; $j = $j + $k)
{
if ($arr[$j] > $arr[$j + $k])
{
$tmp = $arr[$j + $k];
$arr[$j + $k] = $arr[$j];
$arr[$j] = $tmp;
}
}
}
$k = floor($k / 2);
}
return $arr;
}
// print_r(shellSort($arr));
/*
*堆排序
*调整子堆的为大根堆的过程,$s为子堆的根的位置,$m为堆最后一个元素位置
*/
function heapAdjust(&$arr, $s, $m)
{
$tmp = $arr[$s];
// 在调整为大根堆的过程中可能会影响左子堆或右子堆
// for循环的作用是要保证子堆也是大根堆
for ($j = 2*$s + 1; $j <= $m; $j = 2*$j + 1)
{
// 找到根节点的左右孩子中的最大者,然后用这个最大者与根节点比较,
// 若大则进行调整,否则符合大根堆的 特点跳出循环
if ($j < $m && $arr[$j] < $arr[$j + 1])
{
$j++;
}
if ($tmp >= $arr[$j] )
{
break;
}
$arr[$s] = $arr[$j];
$s = $j;
}
$arr[$s] = $tmp;
}
// 堆排序
function heapSort($arr)
{
$len = count($arr);
// 依次从子堆开始调整堆为大根堆
for ($i = floor($len / 2 - 1); $i >= 0; $i--)
{
heapAdjust($arr, $i, $len - 1);
}
// 依次把根节点调换至最后一个位置,再次调整堆为大根堆,找到次最大值,
// 依次类推得到一个有序数组
for ($n = $len - 1; $n > 0; $n--)
{
$tmp = $arr[$n];
$arr[$n] = $arr[0];
$arr[0] = $tmp;
heapAdjust($arr, 0, $n - 1);
}
return $arr;
}
print_r(heapSort($arr));