前言
关于对数组的排序,在算法中有很多方法,较为简单的有冒泡,选择,插入等一些使人熟知的算术方法,在当今这个追求效率的社会,算法的好坏对程序本身有着重要的影响。而我们在判定算法好坏的时候,时间复杂度是一个重要的标尺,
而对数组排序中,插入排序和快速排序的效率要比冒泡和选择排序的效率要高,而今天就来聊一聊插入排序和快速排序的原理和实现。
插入排序
插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的有序数据,把排序的数组分成两部分:第一部分包含了这个数组的所有元素,但将最后一个元素除外(让数组多一个空间才有插入的位置),而第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中。
原理示意图
通俗易懂的说就是:
我们在对数组进行排序是,可以将数组的第一个数字看成是一个有序的数组,而后面的数字是一个无序的数组。遍历后面的无序数组和前面有序的数组进行比较,当发现需要插入时,有序数组向后挪移一位,插入数据。
案列(从小到大排序):
有一个数组:
$arr = array(1,2,10,5,3);
假设第一个数1是有序数组。即:
有序(1)无序(2 , 10 , 5 , 3);
遍历无序数组
for($i = 1; $i < $total; $i++){
$insert = $arr[$i];//先记录带插入的数据;
$j = $i - 1;
利用while循环进行判断插入的位置
while($j >= 0 && $arr[$j] > $insert){
判断条件$j必须大于等于0,当前面已排完序的数比待排序的数大,这是就需要先前的数向后挪一位即:
$arr[$j + 1] = $arr[$j];
$j--;
在这里不要担心$arr[$i]被覆盖了,我们已经在for循环之后记录的待排序的数值。
当不满足while的循环判断条件的时候跳出循环,并赋值
$arr[$j + 1] = $insert;
在这里可以进行判断当没有进入循环的时候,$j + 1 = $i 这时不用进行赋值。
代码:
<?php
$arr = array(1,2,10,5,3);
function insertSort(&$arr){
$total = count($arr);
for($i = 1; $i < $total; $i++){
$insert = $arr[$i];//先记录带插入的数据;
$j = $i - 1;
while($j >= 0 && $arr[$j] > $insert){
$arr[$j + 1] = $arr[$j];
$j--;
}
if($j +1 != $i){
$arr[$j + 1] = $insert;
}
}
}
insertSort($arr);
echo '<pre>';
var_dump($arr);
数字流程示意图:
插入排序的时间复杂度为O(n^2)。是稳定的排序方法。
快速排序
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
快速排序的示例:
有一个数组:
$arr = array(6,2,7,3,8,9);
我们选取第一个数字为界:
$k=$arr[0];//记录k的值 把数组分成两个部分,比k小的在左边,比k大的在右边。
定义两个数组一个存储比k小的数的值,一个存储比k大的值。
然后遍历数组,和$k的值进行比较,遍历完成后,使用递归,不断的分解数组,直到不能再分解为止。
$x=quickSort($x);
$y=quickSort($y);
return array_merge($x,array($k),$y);//数组合并。
代码(易于理解的一种写法):
<?php
$arr = array(6,2,7,3,8,9);
function quickSort(&$arr){
if(count($arr)>1){
$k=$arr[0];//记录k的值 把数组分成两个部分,比k小的在左边,比k大的在右边。
$x=array();
$y=array();
$_size=count($arr);
for($i=1;$i<$_size;$i++){
if($arr[$i]<=$k){
$x[]=$arr[$i];
}else if($arr[$i]>$k){
$y[]=$arr[$i];
}
}
$x=quickSort($x);
$y=quickSort($y);
return array_merge($x,array($k),$y);//数组合并。
}else{
return $arr;
}
}
echo '<pre>';
var_dump(quickSort($arr));
(注意:这种方法虽然符合快速排序的思想,但是会在递归过程中创建大量的数组存放数据,当数据量大的时候会造成 Allowed memory size of 134217728 bytes exhausted也就是内存耗尽)
总结
插入排序和快速排序的差别:插入排序的效率比快速排序的效率要低。我们可以用一个存放20万个数据数组,使用两种方法进行比较。
<span style="font-size:18px;"> $arr = array();
for($i = 0; $i < 200000; $i++){
$arr[] = rand(1, 3000);
}</span>
通过执行前后时间的对比
插入排序:
快速排序:
可以看出插入排序的执行时间超过了php的默认时间。而快速排序用了7秒