前言
之前上学的时候确实是学过排序,但是那时候都是什么选择排序,冒泡排序的,非常容易整混淆,后来准备系统的学习一下10大排序,因为本人学的语言是php,所以准备用php把逻辑代码写出来,本来想截图的,后来想想别人要用的话截图不方便,那就直接粘代码,大家想用的可以直接粘。
一,选择排序
过程简单描述:
首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。其次,在剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。如此往复,直到将整个数组排序。这种方法我们称之为选择排序。
个人理解:
从第一个开始通过遍历,把这个值和后面的每个值都进行比较,如果遇到比这个值小的就进行交换,直到循环完成。
//选择排序代码
class select{
public function SelectSort($array){
$n=count($array);
for ($i=0;$i<$n-1;$i++){
$min=$i;
for ($j=$i+1;$j<$n;$j++){
if ($array[$min]>$array[$j]){
$min=$j ;
}
}
$temp=$array[$i];
$array[$i]= $array[$min];
$array[$min]= $temp;
}
return $array;
}
}
二,插入排序
过程简单描述:
1、从数组第2个元素开始抽取元素。
2、把它与左边第一个元素比较,如果左边第一个元素比它大,则继续与左边第二个元素比较下去,直到遇到不比它大的元素,然后插到这个元素的右边。
3、继续选取第3,4,….n个元素,重复步骤 2 ,选择适当的位置插入。
个人理解:
从第二个值开始,每个值都跟前面的值进行比较,然后找到合适的位置进行插入。
//插入排序的代码
class insert{
public function insertSort($array){
$n= count($array);
if (empty($array)||$n<2){
return $array;
}
for ($i=1;$i<$n;$i++){
$temp = $array[$i];
$k=$i-1;
while ($k>=0&&$array[$k]>$temp){
$k--;
}
for ($j=$i;$j>$k+1;$j--){
$array[$j]=$array[$j-1];
}
$array[$k+1]=$temp;
}
return $array;
}
}
三,冒泡排序
过程简单描述:
1、把第一个元素与第二个元素比较,如果第一个比第二个大,则交换他们的位置。接着继续比较第二个与第三个元素,如果第二个比第三个大,则交换他们的位置….
我们对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对,这样一趟比较交换下来之后,排在最右的元素就会是最大的数。
除去最右的元素,我们对剩余的元素做同样的工作,如此重复下去,直到排序完成。
个人理解:
从第一个开始遍历,把遍历的数字和其后面的进行比较交换位置,小的在前面大的在后面,这里也有一个可以优化的地方,就是当遍历一遍以后发现所有比较都没有交换的时候说明已经遍历成功了,已经完成了排序。
//冒泡排序的代码
class bubble{
public function bubbleSort($array){
$n=count($array);
if (empty($array)||$n<2){
return $array;
}
for($i=0;$i<$n;$i++){
$a=true;
for ($j=0;$j<$n-$i-1;$j++){
if ($array[$j+1]<$array[$j]){
$a=false;
$temp=$array[$j];
$array[$j]=$array[$j+1];
$array[$j+1]=$temp;
}
}
if (!$a){
break;
}
}
return $array;
}
}
四,希尔排序
过程简单描述:
希尔排序可以说是插入排序的一种变种。无论是插入排序还是冒泡排序,如果数组的最大值刚好是在第一位,要将它挪到正确的位置就需要 n - 1 次移动。也就是说,原数组的一个元素如果距离它正确的位置很远的话,则需要与相邻元素交换很多次才能到达正确的位置,这样是相对比较花时间了。
希尔排序就是为了加快速度简单地改进了插入排序,交换不相邻的元素以对数组的局部进行排序。
希尔排序的思想是采用插入排序的方法,先让数组中任意间隔为 h 的元素有序,刚开始 h 的大小可以是 h = n / 2,接着让 h = n / 4,让 h 一直缩小,当 h = 1 时,也就是此时数组中任意间隔为1的元素有序,此时的数组就是有序的了。
个人理解:
这边排序看到时间有点长,理解起来有点难,现在感觉是当数据量比较大的时候,先通过少量的插入排序,进而减少最后一个插入排序的过程。
//希尔排序的代码
class shell{
public function shellSort($array){
$n=count($array);
if (empty($array)||$n<2){
return $array;
}
for ($h=intval($n/2);$h>0;$h=intval($h/2)){
if (empty($h)){
break;
}
for ($i=$h;$i<$n;$i++){
$this->insert($array,$h,$i);
}
echo '</br>';
}
return $array;
}
private function insert(&$array,$h,$i){
$temp=$array[$i];
for ($j=$i-$h;$j>=0&&$temp<$array[$j];$j-=$h){
$array[$j+$h]=$array[$j];
}
$array[$j+$h]=$temp;
}
}
五,归并排序
过程简单描述:
将一个大的无序数组有序,我们可以把大的数组分成两个,然后对这两个数组分别进行排序,之后在把这两个数组合并成一个有序的数组。由于两个小的数组都是有序的,所以在合并的时候是很快的。
通过递归的方式将大的数组一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了,之后再把两个数组大小为1的合并成一个大小为2的,再把两个大小为2的合并成4的 ….. 直到全部小的数组合并起来。
个人理解:
分而治之,先把数据分成两份(分)在排序(治),直到排序的过程为单个的时候,合到一起。第五个了理解起来还行,但是真正写代码的时候遇到了好多问题,而且记起来也很难只能说理解,下次能用到的时候看一看应该就能想起来。
//归并排序的代码
class merge2{
public function mergeSort(&$array,&$temp,$left,$right){
$n= count($array);
if (empty($array)||$n<2){
return $array;
}
if ($left<$right){
$center=intval(($left+$right)/2);
$this->mergeSort($array,$temp,$left,$center);
$this->mergeSort($array,$temp,$center+1,$right);
$this->merge($array,$temp,$left,$center,$right);
}
return $array;
}
public function merge(&$array,&$temp,$left,$center,$right){
$i=$left;
$j=$center+1;
for ($k=$left;$k<=$right;$k++){
if ($i>$center){
$temp[$k]=$array[$j++];
}elseif ($j>$right){
$temp[$k]=$array[$i++];
}elseif ($array[$i]<=$array[$j]){
$temp[$k]=$array[$i++];
}else{
$temp[$k]=$array[$j++];
}
}
for ($k=$left;$k<=$right;$k++){
$array[$k]=$temp[$k];
}
}
}
六,快速排序
过程简单描述:
我们从数组中选择一个元素,我们把这个元素称之为中轴元素吧,然后把数组中所有小于中轴元素的元素放在其左边,所有大于或等于中轴元素的元素放在其右边,显然,此时中轴元素所处的位置的是有序的。也就是说,我们无需再移动中轴元素的位置。
从中轴元素那里开始把大的数组切割成两个小的数组(两个数组都不包含中轴元素),接着我们通过递归的方式,让中轴元素左边的数组和右边的数组也重复同样的操作,直到数组的大小为1,此时每个元素都处于有序的位置。
个人理解:
跟归并排序有点像,但是它是选取一个元素,然后通过大小进行分割,再把分割的进行相同的操作直到不能分为止(数组数量为1)。
//快速排序的代码
class quick{
public function quickSort(&$array,$left,$right){
if ($left<$right){
$mid=$this->partition($array,$left,$right);
$array=$this->quickSort($array,$left,$mid-1);
$array=$this->quickSort($array,$mid+1,$right);
}
return $array;
}
private function partition(&$array,$left,$right){
$pivot=$array[$left];
$i=$left+1;
$j=$right;
while (true){
while ($i<=$j&&$array[$i]<=$pivot)$i++;
while ($i<=$j&&$array[$j]>=$pivot)$j--;
if ($i>=$j){
break;
}
$temp=$array[$i];
$array[$i]=$array[$j];
$array[$j]=$temp;
}
$array[$left]=$array[$j];
$array[$j]=$pivot;
return $j;
}
}
七,堆排序
过程简单描述:
堆的特点就是堆顶的元素是一个最值,大顶堆的堆顶是最大值,小顶堆则是最小值。
堆排序就是把堆顶的元素与最后一个元素交换,交换之后破坏了堆的特性,我们再把堆中剩余的元素再次构成一个大顶堆,然后再把堆顶元素与最后第二个元素交换….如此往复下去,等到剩余的元素只有一个的时候,此时的数组就是有序的了。
个人理解:
先去学习了一下什么是堆,然后知道了一个父节点n下的子节点为2n+1和2n+2,通过这种逻辑先把数据排序,然后通过第一个节点和最后一个节点互换,在进行控制数量的排序,最后完成堆排序。
//堆排序的代码
class head{
public function headSort($array){
$n= count($array);
for ($i=intval(($n-2)/2);$i>=0;$i--){
$this->downAdjust($array, $i, $n - 1);
}
for ($i=$n-1;$i>=1;$i--){
$temp=$array[$i];
$array[$i]=$array[0];
$array[0]=$temp;
$this->downAdjust($array, 0, $i - 1);
}
return $array;
}
public function downAdjust(&$array,$parent,$n){
$temp=$array[$parent];
$child=((2*$parent)+1);
while ($child<=$n){
if (($child+1<=$n)&&($array[$child]<$array[$child+1])){
$child++;
}
if ($array[$child]<=$temp) break;
$array[$parent]=$array[$child];
$parent=$child;
$child=2*$parent+1;
$array[$parent]=$temp;
}
}
}
八,计数排序
过程简单描述:
计数排序是一种适合于最大值和最小值的差值不是不是很大的排序。
基本思想:就是把数组元素作为数组的下标,然后用一个临时数组统计该元素出现的次数,例如 temp[i] = m, 表示元素 i 一共出现了 m 次。最后再把临时数组统计的数据从小到大汇总起来,此时汇总起来是数据是有序的。
个人理解:
先是创建了一个数组,key值为不同数组的值,value为值数量,然后从0开始遍历到数组的最大值,遍历这个数组,如果存在key值等于遍历的值,就放入新的数组中。
//计数排序的代码(优化)
class count{
public function headCount($array){
$n= count($array);
if (empty($array)||$n<2){
return $array;
}
$max=max($array);
$min=min($array);
$temp=[];
$d=$max-$min+1;
for ($i=0;$i<$n;$i++){
$temp[$array[$i]]++;
}
$k=0;
$arrays=[];
for ($i=0;$i<=$d;$i++){
for ($j=$temp[$i];$j>0;$j--){
$arrays[$k++]=$i;
}
}
return $arrays;
}
}
九,桶排序
过程简单描述:
桶排序就是把最大值和最小值之间的数进行瓜分,例如分成 10 个区间,10个区间对应10个桶,我们把各元素放到对应区间的桶中去,再对每个桶中的数进行排序,可以采用归并排序,也可以采用快速排序之类的。
之后每个桶里面的数据就是有序的了,我们在进行合并汇总。
个人理解:
学这个算法的时候,感觉跟计数算法很像,先是生成了一个区间的空数组,然后遍历找出每个区间数组的数量,最后把数组遍历出来完成排序。不用像计数排序那样必须从0开始创建数组,更加的灵活。
//桶排序的代码
class bucket{
public function bucketSort($array){
$n= count($array);
if (empty($array)||$n<2){
return $array;
}
$max=max($array);
$min=min($array);
$bucket=array_fill($min,$max-$min+1,0);
foreach ($array as $value){
$bucket[$value]++;
}
$arrays=[];
foreach ($bucket as $key=>$item){
for ($i=1;$i<=$item;$i++){
$arrays[]=$key;
}
}
return $arrays;
}
}
十,基数排序
过程简单描述:
基数排序的排序思路是这样的:先以个位数的大小来对数据进行排序,接着以十位数的大小来多数进行排序,接着以百位数的大小……
排到最后,就是一组有序的元素了。不过,他在以某位数进行排序的时候,是用“桶”来排序的。
由于某位数(个位/十位….,不是一整个数)的大小范围为0-9,所以我们需要10个桶,然后把具有相同数值的数放进同一个桶里,之后再把桶里的数按照0号桶到9号桶的顺序取出来,这样一趟下来,按照某位数的排序就完成了。
个人理解:
最后一个了,本来以为很简单,最后花了几个小时,找了一下教程终于写出来了,就是先找出所有数中的最大值,判断他有几位,然后进行遍历循环。从个位数的比较开始进行桶排序,十位百位一直到最大位数的排序,最后排序成功,下面这个代码是根据自己的感觉写的,最后测试了一下还可以。
//基数排序的代码
class radio{
public function radioSort(&$array){
$n= count($array);
if (empty($array)||$n<2){
return $array;
}
$max=max($array);
$min=min($array);
$num=1;
while (intval($max/10)>0){
$num++;
$max=intval($max/10);
}
for ($i=1;$i<=$num;$i++){
$bucket=array_fill(0,10,0);
for ($j=0;$j<$n;$j++){
if(!$array[$j]){
continue;
}
if ($bucket[$this->getN($array[$j],$i)]==0){
$bucket[$this->getN($array[$j],$i)]=[$array[$j]]?:0;
}else{
$bucket[$this->getN($array[$j],$i)][]=$array[$j];
}
}
$k=0;
foreach ($bucket as $key=>$item){
if ($item){
for ($a=0;$a<count($item);$a++){
$array[$k]=$item[$a];
$k++;
}
}
}
}
return $array;
}
//获取第几位上的数组
private function getN($num,$N){
$value=10;
for ($i=1;$i<$N;$i++){
$value=$value*10;
}
$M=(int)(($num%$value/($value/10)));
return $M;
}
}
总结
最开始学前几个排序的时候感觉很简单,最后还是用了1周多的时间把所有的排序才写完,学完后,感觉有些还是有些混淆,算法还真的是用无止境qwq。