参考:http://www.cnblogs.com/eniac12/p/5329396.html
1.1冒泡排序(BubbleSort)
原理
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
<?php
/**
* 冒泡排序
* 数据结构----------------数组
* 最差时间复杂度-----------O(n^2)
* 最优时间复杂度-----------O(n)
* 平均时间复杂度-----------O(n^2)
* 空间复杂度---------------O(1)
* 稳定性------------------稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
function BubbleSort($arr)
{
$length = count($arr);
for ($i = 0; $i < $length - 1; $i++) { // 每次最大元素移到数组最后
for ($j = 0; $j < $length - 1 - $i; $j++) { // 内部循环次数=数组长度-已经排序好的个数-1
if ($arr[$j] > $arr[$j + 1]) { // 比较相邻两个元素,较大的后移
$t = $arr[$j];
$arr[$j] = $arr[$j + 1];
$arr[$j + 1] = $t;
}
}
}
return $arr;
}
print_r(BubbleSort($arr));
1.2鸡尾酒排序(CocktailSort)
鸡尾酒排序也就是定向冒泡排序, 鸡尾酒搅拌排序, 搅拌排序 (也可以视作选择排序的一种变形), 涟漪排序, 来回排序 or 快乐小时排序, 是冒泡排序的一种变形。此演算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。
原理:数组中的数字本是无规律的排放,先找到最小的数字,把他放到第一位,然后找到最大的数字放到最后一位。然后再找到第二小的数字放到第二位,再找到第二大的数字放到倒数第二位。以此类推,直到完成排序。
<?php
/**
* 鸡尾酒排序
* 数据结构----------------数组
* 最差时间复杂度-----------O(n^2)
* 最优时间复杂度-----------O(n)
* 平均时间复杂度-----------O(n^2)
* 空间复杂度--------------O(1)
* 稳定性-----------------稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
function CocktailSort($arr)
{
$left = 0; // 定义左边界
$right = count($arr) - 1; // 定义右边界
while ($left < $right) {
for ($i = $left; $i < $right; $i++) { // 从左向右,将最大元素放在后面
if ($arr[$i] > $arr[$i + 1]) {
$t = $arr[$i];
$arr[$i] = $arr[$i + 1];
$arr[$i + 1] = $t;
}
}
$right--; // 右边界缩小
for ($i = $right; $i > $left; $i--) { // 从右向左,将最小元素放在前面
if ($arr[$i-1] > $arr[$i]) {
$t = $arr[$i -1];
$arr[$i - 1] = $arr[$i];
$arr[$i] = $t;
}
}
$left++; // 左边界增大
}
return $arr;
}
print_r(CocktailSort($arr));
2.选择排序(SelectionSort)
原理:每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完.。
<?php
/**
* 选择排序
* 数据结构----------------数组
* 最差时间复杂度-----------O(n^2)
* 最优时间复杂度-----------O(n^2)
* 平均时间复杂度-----------O(n^2)
* 空间复杂度--------------O(1)
* 稳定性-----------------不稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
function SelectionSort($arr)
{
$length = count($arr);
for ($i = 0; $i < $length - 1; $i++) { // $i为已经排序序列的末尾下标
$min = $i; // 暂存未排列序列的最小值下标
for ($j = $i + 1; $j < $length; $j++) { // 遍历未排列序列
if ($arr[$j] < $arr[$min]) { // 找出排列序列最小值,下标赋给$min
$min = $j;
}
}
if ($min != $i) { // 如果找到最小值,放到已排列序列末尾
$t = $arr[$min];
$arr[$min] = $arr[$i];
$arr[$i] = $t;
}
}
return $arr;
}
print_r(SelectionSort($arr));
3.1插入排序——直接插入排序(StraightInsertionSort)
原理
![](/qrcode.jpg)
- 从第一个元素开始,该元素可以认为已经被排序
- 取出下一个元素,在已经排序的元素序列中从后向前扫描
- 如果该元素(已排序)大于新元素,将该元素移到下一位置
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
- 将新元素插入到该位置后
- 重复步骤2~5
<?php
/**
* 直接插入排序
* 数据结构----------------数组
* 最差时间复杂度-----------O(n^2):输入序列是降序排列的
* 最优时间复杂度-----------O(n):输入序列是升序排列的
* 平均时间复杂度-----------O(n^2)
* 空间复杂度--------------O(1)
* 稳定性-----------------稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
function StraightInsertionSort($arr)
{ // 数组第一个元素默认已被排序
for ($i = 1; $i < count($arr); $i++) { // 未排序序列从数组第二个元素开始
$get = $arr[$i]; // 获取未排列序列第一个元素为要比较的元素
$j = $i - 1; // 指针指向已排序序列最后一个元素
while ($j >= 0 && $arr[$j] > $get) { // 当指针指向的元素比要比较的元素大
$arr[$j + 1] = $arr[$j]; // 则将指针指向的元素向后移动一位
$j--; // 指针前移
}
$arr[$j + 1] = $get; // 直到指针指向的元素与要比较元素小或者相等,则要比较元素插入到指针指向元素后
}
return $arr;
}
print_r(StraightInsertionSort($arr));
3.2插入排序——二分查找排序(BinarySearchSort)
原理:首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
<?php
/**
* 二分查找排序
* 数据结构----------------数组
* 最差时间复杂度-----------O(n^2)
* 最优时间复杂度-----------O(nlogn)
* 平均时间复杂度-----------O(n^2)
* 空间复杂度--------------O(1)
* 稳定性-----------------稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
function BinarySearchSort($arr)
{ // 数组第一个元素默认已被排序
for ($i = 1; $i < count($arr); $i++) { // 未排列序列从数组第二个元素开始
$get = $arr[$i]; // 获取未排列序列第一个元素为要比较元素
$left = 0; // 定义已排列序列左边界
$right = $i -1; // 右边界
while ($left <= $right) {
$mid = floor(($left + $right) / 2); // 定义中间数,将已排列序列一分为二
if ($arr[$mid] > $get) { // 如果中间数大于比较元素,则比较元素属于前半段
$right = $mid -1; // 右边界左移
} else { // 否则比较元素属于后半段
$left = $mid + 1; // 左边界右移
}
}
for ($j = $i -1; $j >= $left; $j--) { // 最后的$left就是待插入位置
$arr[$j + 1] = $arr[$j]; // 将待插入位置的右边整体向右移动一个单位
}
$arr[$left] = $get; // 将比较元素插入该空位
}
return $arr;
}
print_r(BinarySearchSort($arr));
3.3插入排序——希尔排序(ShellSort)
希尔排序,也叫递减增量排序,是插入排序的一种更高效的改进版本。希尔排序是不稳定的排序算法。
原理:希尔排序通过将比较的全部元素分为几个区域来提升插入排序的性能。这样可以让一个元素可以一次性地朝最终位置前一大步。然后算法再取越来越小的步长进行排序,算法的最后一步就是普通的插入排序,但是到了这步,需排序的数据几乎是已排好的了(此时插入排序较快)。
增量序列:由Knuth提出,递归表达式为:h = 3 * h + 1;减小增量:h = (h - 1) / 3;此公式产生的逆置序列为:..., 314, 121, 40, 13, 4, 1。
<?php
/**
* 希尔排序
* 数据结构----------------数组
* 最差时间复杂度-----------O(n^2)
* 最优时间复杂度-----------O(n^1.3)
* 平均时间复杂度-----------O(nlogn)
* 空间复杂度--------------O(1)
* 稳定性-----------------不稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
function ShellSort($arr)
{
$length = count($arr);
$h = 0;
while ($h <= $length) { // 定义增量序列
$h = 3 * $h + 1;
}
while ($h >= 1) {
for ($i = $h; $i < $length; $i++) {
$j = $i - $h;
$get = $arr[$i]; // 暂存要比较的元素
while ($j >= 0 && $arr[$j] > $get) { // 组内判断,若组内元素大于该元素
$arr[$j + $h] = $arr[$j]; // 则两者位置互换
$j = $j - $h; // 指针继续向前移动增量的距离,继续比较
}
$arr[$j + $h] = $get;
}
$h = ($h - 1) / 3; // 递减增量
}
return $arr;
}
print_r(ShellSort($arr));
4.归并排序(MergeSort)
原理:归并排序的实现分为递归实现与非递归(迭代)实现。递归实现的归并排序是算法设计中分治策略的典型应用,我们将一个大问题分割成小问题分别解决,然后用所有小问题的答案来解决整个大问题。非递归(迭代)实现的归并排序首先进行是两两归并,然后四四归并,然后是八八归并,一直下去直到归并了整个数组。
归并排序算法主要依赖归并(Merge)操作。归并操作指的是将两个已经排序的序列合并成一个序列的操作,归并操作步骤如下:
- 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
- 设定两个指针,最初位置分别为两个已经排序序列的起始位置
- 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
- 重复步骤3直到某一指针到达序列尾
- 将另一序列剩下的所有元素直接复制到合并序列尾
<?php
/**
* 归并排序
* 数据结构----------------数组
* 最差时间复杂度-----------O(nlogn)
* 最优时间复杂度-----------O(nlogn)
* 平均时间复杂度-----------O(nlogn)
* 空间复杂度--------------O(n)
* 稳定性-----------------稳定
*/
$arr = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
$arr2 = [1, 3, 34, 2, 32, 2, 78, -43, 53, -35, 0];
$length = count($arr);
$length2 = count($arr2);
// 递归实现
function MergeSortRecursion(&$arr, $left, $right)
{
if ($left == $right) {
return;
}
$mid = floor(($left + $right) / 2);
MergeSortRecursion($arr, $left, $mid);
MergeSortRecursion($arr, $mid + 1, $right);
Merge($arr, $left, $mid, $right);
}
// 迭代实现
function MergeSortIteration(&$arr, $length)
{
// 分为两个子数组,前一个为[$left, ... , $mid], 后一个为[mid + 1, ... , $right]
for ($i = 1; $i < $length; $i *= 2) { // 子数组大小,初始值为1,每轮翻倍
$left = 0;
while ($left + $i < $length) { // 当后一个子数组存在时,需要归并
$mid = $left + $i - 1;
$right = $mid + $i < $length ? $mid + $i : $length - 1; // 当后一个子数组长度不够时,用右边界
Merge($arr, $left, $mid, $right);
$left = $right + 1; // 前一个子数组左边界向右移动
}
}
}
// 合并两个已经排列好的序列
function Merge(&$arr, $left, $mid, $right)
{
$length = $right - $left + 1; // 待排序的数组长度
$temp = []; // 暂存排序好的元素
$index = 0;
$i = $left; // 前一个数组的起始元素
$j = $mid + 1; // 后一个数组的起始元素
while ($i <= $mid && $j <= $right) {
$temp[$index++] = $arr[$i] <= $arr[$j] ? $arr[$i++] : $arr[$j++]; // 比较两个指针所指向的元素,选择小的元素放入暂存数组,并将改指针后移
}
// 将剩余未比较的元素放入暂存数组末尾
while ($i <= $mid) {
$temp[$index++] = $arr[$i++];
}
while ($j <= $right) {
$temp[$index++] = $arr[$j++];
}
// 更新数组的排序
for ($k = 0; $k < $length; $k++) {
$arr[$left++] = $temp[$k];
}
}
MergeSortRecursion($arr, 0, $length - 1);
echo "递归实现:";
print_r($arr);
MergeSortIteration($arr2, $length2);
echo "迭代实现:";
print_r($arr2);
5.堆排序(HeapSort)
原理: