常见的排序方式
插入排序
待排序数据较少时用时少
从数组的第二个元素(即待插入的元素)开始,分别与之前的元素进行比较,若满足一定的条件就将此元素插入此位置。
例对[8,9,6,7,2]进行排序。
第一次排序:9为待插入的元素(i=1),与其之前元素8(j=0)进行比较,8>9,不满足条件,9要插入的位置为1(j=0+1),即9位置不发生变化;此时待排序元素顺序为[8,9,6,7,2]
第二次排序:6为带插入的元素(i=2).
- 首先与其之前元素9(j=1)进行比较,j>=0并且9>6,满足条件,把9放入6的位置上($ary[$j+1]=$ary[$j];($ary[2]=$ary[1])
),此时待排序元素顺序为[8,9,9,7,2],j=0;
- 继续进行比较,6与数组的第一个元素(即序号为j=0)进行比较,依然满足条件,把8放入9的位置上($ary[$j+1]=$ary[$j];($ary[1]=$ary[0])
),此时待排序元素顺序为[8,8,9,7,2],j=-1(发生了自减);
- 由于j>=0不再成立,因此while部分到此结束,把6放入位置0(此时j+1=0)处,此时待排序元素顺序为[6,8,9,7,2]
接下来依次进行剩下排序
function InsertSort(array $ary){
$lenth=count($ary);//获取数组长度即待排序数据个数
for ($i=1;$i<$lenth;$i++){
$val=$ary[$i];
$j=$i-1;
while ($j>=0 && $ary[$j]>$val){//升序排序
$ary[$j+1]=$ary[$j];
$j=$j-1;
}
$ary[$j+1]=$val;//把元素插入指定位置
}
return $ary;
}
冒泡排序
流行低效
原理:反复交换相邻的未按次序排列的元素
例对[8,9,6,7,2]进行排序。
第一次排序:
- i=0;j=4;
- 4>1(i+1),执行第二个for部分
- 位置4(j)上元素为2,位置3(j-1)上元素为7,2<7进行交换,此时元素顺序变化为[8,9,6,2,7],j值为3
- 3>1(i+1),继续执行第二个for部分
- 位置3(j)上元素仍为2,位置2(j-1)上元素为6,2<6进行交换,此时元素顺序变化为[8,9,2,6,7],j值为2
- 依次比较,直到最小元素(2)冒泡至位置i(0),成为第一个元素,此时元素顺序变化为[2,8,9,6,7],j值为0,i为0,0(j)<1(i+1),不再执行第二个for部分,i自加,值为1,重复之上步骤将第二小元素(6)冒泡至位置i(1)成为第二个元素
- 以此继续比较,直到i为3(即倒数第二个元素,剩下最后一个元素无须比较)
function BubbleSort(array $ary){
for ($i=0;$i<count($ary);$i++){
for($j=count($ary)-1;$j>=$i+1;$j--){
if($ary[$j]<$ary[$j-1]){
$mid= $ary[$j];
$ary[$j]=$ary[$j-1];
$ary[$j-1]=$mid;
}
}
}
return $ary;
}
快速排序法
使用了递归
原理:根据数据里的第一个元素val把所有元素分为两个数组,比val大的放入right数组,比val小的放入left数组;按照此方法把right、left数组继续分割,直到分割为一个个元素的数组;最后把这些数组合并即可
function QucikSort(array $ary){
if(count($ary)>1){
$val=$ary[0];
$left=array();
$right=array();
$size=count($ary);
for ($i=1;$i<$size;$i++){
//根据首元素把所有元素分为两部分
if($ary[$i]<=$val){
$left[]=$ary[$i];
}else if($ary[$i]>$val){
$right[]=$ary[$i];
}
}
$left=QucikSort($left);//对较小元素进行再次分割
$right=QucikSort($right);//对较大元素进行再次分割
//合并元素
return array_merge($left,array($val),$right);
}else{
return $ary;
}
}
选择排序法
原理:首先通过依次比较选择出最小的值,将最小值放入数组开始位置,重复这一步骤,直到完成所有排序。
function SelectSort(array $ary){
$count=count($ary);
for($i=0;$i<$count-1;$i++){
//找出最小值
$min=$i;
for($j=$i+1;$j<$count;$j++){
if($ary[$min]>$ary[$j]){
$min=$j;
}
}
//把最小值放入位置i处
if($min!=$i){
$temp=$ary[$min];
$ary[$min]=$ary[$i];
$ary[$i]=$temp;
}
}
return$ary;
}
归并排序法
使用了递归
原理:把待排序数组从中间分开,一分为二,并按此方法(即递归),拆分为单个元素数组,按照顺序(12\34\56\78)两两组合为有序数组,再将生成的有序数组合并为大的有序数组,重复操作,直到合并成一个有序数组。
例:对[8,9,6,7,2]使用归并排序法
- 第一:拆分[8,9] [6,7,2]
- 第二:拆分左侧数组[8][9]
- 第三:合并为有序数组[8,9]
- 第四:拆分右侧数组[6,7,2]
- 第五:继续拆分右侧数组[6][7,2]
- 第六:[6]无需拆分,继续拆分右侧数组[7][2]
- 第七:合并为有序数组[2,7]
- 第八:合并为有序数组[2,6,7]
- 第九:两个大数组[8,9][2,6,7]合并为有序数组[2,6,7,8,9]
function Merge($ary,$bry){
$cry=array();
while (count($ary) && count($bry)){
$cry[]=$ary[0]<$bry[0] ? array_shift($ary) : array_shift($bry);
}
return array_merge( $cry,$ary,$bry);
}
//主排序程序
function MergeSort(array $ary){
$count=count($ary);
if($count<=1){
return $ary;
}
$mid=intval($count/2);
$left=array_slice($ary, 0,$mid);
$right=array_slice($ary, $mid);
$left=MergeSort($left);
$right=MergeSort($right);
return Merge($left,$right);
}
思考
快速排序法,归并排序法等其他使用了递归的排序法,都是把问题分解为一些小问题,这些小问题与原问题问题一样,只是包含的元素更少,更容易解决,递归地求解出这些小问题,如果小问题的规模更小(一般情况下都是分解为单元素的数组),则停止递归,进行求解,最后把解决过的小问题合并,直至合并为一个数组。