- 基本的排序算法
冒泡排序(Bubble Sort)
插入排序(Insertion Sort)
- 常考的排序算法
归并排序(Merge Sort)
快速排序(Quick Sort)
拓扑排序(Topological Sort)
- 其他排序算法
堆排序(Heap Sort)
桶排序(Bucket Sort)
冒泡排序(Bubble Sort)
基本思想
给定一个数组,我们把数组里的元素通通倒入到水池中,这些元素将通过相互之间的比较,按照大小顺序一个一个地像气泡一样浮出水面。
实现
每一轮,从杂乱无章的数组头部开始,每两个元素比较大小并进行交换,直到这一轮当中最大或最小的元素被放置在数组的尾部,然后不断地重复这个过程,直到所有元素都排好位置。其中,核心操作就是元素相互比较。
function bubbleSort($arr)
{
$len = count($arr);
if ($len <= 1) return $arr;
$flag = true;
for ($i = 0; $i< $len-1&&$flag;$i++) {
$flag=false;
for($j = $len-1; $j> $i;$j--) {
if ($arr[$j-1] > $arr[$j]) {
$this->swap($arr, $j-1, $j);
$flag = true;
}
}
}
return $arr;
}
private function swap(&$arr, $i, $j)
{
$tmp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $tmp;
}
空间复杂度
假设数组的元素个数是 n,由于在整个排序的过程中,我们是直接在给定的数组里面进行元素的两两交换,所以空间复杂度是 O(1)。
时间复杂度
冒泡排序的时间复杂度是 O(n2)。它是一种稳定的排序算法。(稳定是指如果数组里两个相等的数,那么排序前后这两个相等的数的相对位置保持不变。)
插入排序(Insertion Sort)
基本思想
不断地将尚未排好序的数插入到已经排好序的部分。
特点
在冒泡排序中,经过每一轮的排序处理后,数组后端的数是排好序的;而对于插入排序来说,经过每一轮的排序处理后,数组前端的数都是排好序的。
function insertionSort($arr)
{
$len = count($arr);
if ($len <= 1) return $arr;
for ($i = 1; $i < $len; $i++) {
$tmp = $arr[$i];
for ($j = $i-1; $j>=0; $j--) {
if ($arr[$j] > $tmp) {
$arr[$j+1] = $arr[$j];
$arr[$j] = $tmp;
} else {
break;
}
}
}
}
空间复杂度
假设数组的元素个数是 n,由于在整个排序的过程中,是直接在给定的数组里面进行元素的两两交换,空间复杂度是 O(1)。
时间复杂度
和冒泡排序一样,插入排序的时间复杂度是 O(n2),并且它也是一种稳定的排序算法。
归并排序(Merge Sort)
基本思想
核心是分治,就是把一个复杂的问题分成两个或多个相同或相似的子问题,然后把子问题分成更小的子问题,直到子问题可以简单的直接求解,最原问题的解就是子问题解的合并。归并排序将分治的思想体现得淋漓尽致。
实现
一开始先把数组从中间划分成两个子数组,一直递归地把子数组划分成更小的子数组,直到子数组里面只有一个元素,才开始排序。
排序的方法就是按照大小顺序合并两个元素,接着依次按照递归的返回顺序,不断地合并排好序的子数组,直到最后把整个数组的顺序排好。
function mergeSort($arr)
{
$len = count($arr);
if ($len <= 1) return $arr;
$mid = intval($len/2);
$left = array_slice($arr, 0, $mid);
$right = array_slice($arr, $mid);
$left = mergeSort($left);
$right = mergeSort($right);
$arr = merge($left, $right);
return $arr;
}
function merge($arrA, $arrB)
{
$arrC = array();
while( count($arrA) && count($arrB) ) {
$arrC[] = ($arrA[0] < $arrB[0]) ? array_shift($arrA) : array_shift($arrB) ;
}
return array_merge($arrC, $arrA, $arrB);
}
空间复杂度
由于合并 n 个元素需要分配一个大小为 n 的额外数组,合并完成之后,这个数组的空间就会被释放,所以算法的空间复杂度就是 O(n)。归并排序也是稳定的排序算法。
时间复杂度
归并算法是一个不断递归的过程。整体的复杂度就是 O(nlogn)。
快速排序(Quick Sort)
基本思想
快速排序也采用了分治的思想。
实现
把原始的数组筛选成较小和较大的两个子数组,然后递归地排序两个子数组。
非最优写法,最优写法见文末
function quickSort($arr)
{
$len = count($arr);
if ($len <= 1) return $arr;
$left = $right = array();
for($i=1; $i<$len; $i++)
{
if($arr[$i] < $arr[0]){
$left[]=$arr[$i];
}else{
$right[]=$arr[$i];
}
}
$left = quickSort($left);
$right = quickSort($right);
return array_merge($left,array($arr[0]),$right);
}
空间复杂度
和归并排序不同,快速排序在每次递归的过程中,只需要开辟 O(1) 的存储空间来完成交换操作实现直接对数组的修改,又因为递归次数为 logn,所以它的整体空间复杂度完全取决于压堆栈的次数,因此它的空间复杂度是 O(logn)。
时间复杂度
算法复杂度为O(nlogn), 最差为O(n2)。
参考链接:
快排的优化算法实现
php实现快速排序算法
php快速排序三种方法 文中第三种