详解四大排序算法

作者: Dsir 分类: PHP 发布时间: 2017年08月04日 07时40分

详解四大排序算法

如何排序?

NBA总决赛正在如火如荼的进行,老詹也正朝着他的第5个总亚军前进着。假设骑士队队员在运动场上排列成一队,如图所示,所有队员已经站好,准备热身,现在需要按身高从低到高
为队员们排队(最矮的站在左边),给他们照一张集体照,应该怎么排队呢?
在排序这件事情上,人与计算机程序相比有以下优势:我可以同时看到所有的队员,并且可以立刻找出最高的一个,毫不费力得测量和比较每一个人的身高。而且队员们不一定要固守特定的空间,他们可以相互推推攘攘就腾出了位置,还能互相前后站立,经过一些具体的调整,毫不费力地给队员们排好队

计算机程序员却不能像人这样通览所有的数据,它只能根据计算机的“比较”操作,在同一时间内对两个队员进行比较,算法 将”比较”的行为视为一个反复出现的问题,在人类看来是非常简单的事情,但程序算法 却只能一步一步得解决具体问题 和遵循一些简单的规则。

算法的本质就是拆分问题,按照最简单的规则,把问题拆分为一步一步交给计算机执行。
看上去这么简单,对吗:

  1. 比较两个数据项
  2. 交换两个数据项,或复制其中一项

重复这两步循环执行,直到全部有序为止。
不要轻视算法,因每种算法具体实现的细节有所不同。

BUBBLE 冒泡排序



冒泡排序算法运行起来非常慢,但概念上它是排序算法中最简单的,适合刚开始研究算法技术时的入门。

首先由一组无序的数字:

我录制了一段冒泡排序的执行过程(需要1-2秒的缓冲):

耐心观看完后,我们可以总结出冒泡排序的规则:

  1. 比较两个数字
  2. 如果左边的数字大,则交换两个数字的位置
  3. 向右移动一个位置,比较下两个数字

    沿着这个顺序比较下去,一直比较到最右端,虽然没有把所有的数字排好序,但是,数字中最大的那一个已经排放在最右边了,这个是一轮比较下来
    可以确定的结果。

    下一轮,我们继续从最左边开始。

    这也是这个算法被称为冒泡排序的原因:因为在算法执行的时候,最大的数据项 总是
    “冒泡”到数组的顶端【数组的排列规则,从左到右0-N】。

代码实现:
$arr=array(1,43,54,62,21,66,32,78,36,76,39);  
function bubbleSort($arr)
{  
  $len=count($arr);
  //该层循环控制 需要冒泡的轮数
  for($i=1;$i<$len;$i++)
  { //该层循环用来控制每轮 冒出一个数 需要比较的次数
    for($k=0;$k<$len-$i;$k++)
    {
       if($arr[$k]>$arr[$k+1])
        {
            $tmp=$arr[$k+1];
            $arr[$k+1]=$arr[$k];
            $arr[$k]=$tmp;
        }
    }
  }
  return $arr;
}

SELECT 选择排序


理解一下选择排序的原理

一组数据,

选择排序的原理,

* 使用选择排序算法对老詹的队友们排序,*

在选择排序中,不再比较两个相邻的队员,因此,需要记录下某个指定队员的高;可以用记事本记下队员的身高,同时还需要准备好一条紫红色的毛巾(不是搞基)。

进行选择排序
就是把所有的队员扫描一遍,从中选择出最矮的一个队员,最矮的这个队员和站在队列最左端的队员交换位置,即占到0号位置,现在最左端的队员是有序的了,不再需要交换位置。注意,在这个算法中有序的队员都排在队列的最左边(数组中较小的下标值),而冒泡排序则是优先排列在队列的右边。

排序从最左边开始,记录本上写下最左端球员的身高,并且在他的脖子上挂上红色毛巾,于是开始用下一个球员的身高和记录本上记录的值比较,如果下一个球员更矮,则在本子上划掉第一个球员的身高,记录第二个队员的身高,同时把红色毛巾从第一个球员的脖子上拿下来,挂在第二个队员的脖子上,继续沿着队列走下去,

一轮下来,毛巾就会落在最矮的队员面前,接着,唯一拥有红毛巾的队员和队列最左边的队员交换位置,现在已经对一个队员排好序了,这期间做了N-1次比较,淡只进行了一次交换。

嗯,老詹对你的建议很满意。

选择排序的代码实现

代码实现:
$arr=array(1,43,54,62,21,66,32,78,36,76,39);  
function bubbleSort($arr)
{  
  $len=count($arr);
  //该层循环控制 需要冒泡的轮数
  for($i=1;$i<$len;$i++)
  { //该层循环用来控制每轮 冒出一个数 需要比较的次数
    for($k=0;$k<$len-$i;$k++)
    {
       if($arr[$k]>$arr[$k+1])
        {
            $tmp=$arr[$k+1];
            $arr[$k+1]=$arr[$k];
            $arr[$k]=$tmp;
        }
    }
  }
  return $arr;
}

INSERT 插入排序


插入排序原理

一段数据:

我录制了一段原理展示:

用插入排序提醒老詹吧

插入排序之前,队员随机站好。从排序过程的中间开始,可以更好地理解插入排序,这时队列已经排好了一半。

局部有序

此时,队友中间有一个作为标记的队员,还是用紫红色毛巾作标记吧,这个作为标记的队员的左边的所有队员已经是局部有序了。这意味着这一部分人之间是按顺序排列的:每个人比他左边的人都搞,然而这些队员在队列中最终的位置还没有确定,因为,当没有被排过序的队员要插入到他们中间的时候,他们的位置还要变动。

注意,局部有序在冒泡排序和选择排序中是不会出现的。在这两个算法中,一组数据项在某个时刻是完全有序的:在插入排序中,一组数据仅仅是局部有序的。

被标记的队员

作为标记的队员,称为“被标记的队员”,他和他右边所有的队员都是未排序的

如图:

下面价格要做的是在局部的 有序组中适当的位置 插入被标记的队员,然而要做到这一点,需要把部分已排序的队员右移腾出空间,为了提供移动所需的空间,就先让被标记的队员出列(在程序中,这个出列的行为,是该数据项被存储在一个临时变量中)

现在移动已经排过序的队员来腾出空间,将局部有序中最高的队员移动到原来被标记队员所在位置,次高的队员移动到原来最高的队员所在位置,以此类推。

局部有序的部分里多了一个队员,而未排序的部分少了一个队员,作为标记的球员,向右移动一个位置,所以他仍然放在未排序部分的最左边的队员勉强,重复这个过程,直到所有未排序的队员都被插入到局部有序队列中的合适位置。

插入排序的核心代码:

function insertSort($arr) {
    $len=count($arr); 
    for($i=1, $i<$len; $i++) {
        $tmp = $arr[$i];
        //内层循环控制,比较并插入
        for($j=$i-1;$j>=0;$j--) {
            if($tmp < $arr[$j]) {
                //发现插入的元素要小,交换位置,将后边的元素与前面的元素互换
                $arr[$j+1] = $arr[$j];
                $arr[$j] = $tmp;
            } else {
                //如果碰到不需要移动的元素,由于是已经排序好是数组,则前面的就不需要再次比较了。
                break;
            }
        }
    }
    return $arr;
}

插入排序的效率(有趣)

这个算法需要多少次比较和复制呢?在第一轮排序中,它最多比较一次,在第二轮最多比较两次,以此类推

1+2+3+…+N-1=N*(N-1)/2 次比较;

复制的次数,大致等于比较的次数,然而,一次复制与一次交换的时间耗费不同,相对于 随机顺序的数据这个算法比冒泡排序快一倍,比选择排序略快,

在任意情况下,插入排序的时间复杂度也为O(N2)。

有趣的是

对于已经有序或者基本有序的数据来说,插入排序要好得多,当数据有序的时候,while循环的条件总是false吗所以它成为了外层循环中的一个简单语句,执行N-1此,算法运行只需要O(N)的时间。这对一个基本有序的文件进行排序是一个简单而有效的方法。

然而,对于逆序排列的数据,每次比较和移动都会执行,在这种情况下,插入排序 并不比冒泡排序快。

MERGE 归并排序


直接上手归并排序?NO!

感受归并排序

一组随机数据:

归并排序流程:

归并排序:时间复杂度为~O(nlogn)--又称合并排序

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,

即把待排序序列分为若干个有序的子序列,再把有序的子序列合并为整体有序序列。

归并排序的一个缺点是它需要存储器有另一个大小等于数据项数目的数组。如果初始数组几乎占满整个存储器,那么归并排序将不能工作,但是如果有足够的空间,归并排序会是一个很好的选择。

<?php  
$arrStoreList = array(3,2,4,1,5);  
$sort = new Merge_sort();  
$sort->stableSort($arrStoreList, function ($a, $b) {    // function ($a, $b)匿名函数  
            return $a < $b;  
});  
//静态调用方式也行  
/*Merge_sort:: stableSort($arrStoreList, function ($a, $b) { 
            return $a < $b; 
});*/  
print_r($arrStoreList);  
  
class Merge_sort{  
  
 public static function stableSort(&$array, $cmp_function = ‘strcmp‘) {  
        //使用合并排序  
        self::mergeSort($array, $cmp_function);  
        return;  
    }  
 public static function mergeSort(&$array, $cmp_function = ‘strcmp‘) {  
        // Arrays of size < 2 require no action.  
        if (count($array) < 2) {  
            return;  
        }  
        // Split the array in half  
        $halfway = count($array) / 2;  
        $array1 = array_slice($array, 0, $halfway);  
        $array2 = array_slice($array, $halfway);  
        // Recurse to sort the two halves  
        self::mergeSort($array1, $cmp_function);  
        self::mergeSort($array2, $cmp_function);  
        // If all of $array1 is <= all of $array2, just append them.  
//array1 与 array2 各自有序;要整体有序,需要比较array1的最后一个元素和array2的第一个元素大小  
        if (call_user_func($cmp_function, end($array1), $array2[0]) < 1) {    
            $array = array_merge($array1, $array2);  
  
            return;  
        }  
        // 将两个有序数组合并为一个有序数组:Merge the two sorted arrays into a single sorted array  
        $array = array();  
        $ptr1 = $ptr2 = 0;  
        while ($ptr1 < count($array1) && $ptr2 < count($array2)) {  
            if (call_user_func($cmp_function, $array1[$ptr1], $array2[$ptr2]) < 1) {  
                $array[] = $array1[$ptr1++];  
            } else {  
                $array[] = $array2[$ptr2++];  
            }  
        }  
        // Merge the remainder  
        while ($ptr1 < count($array1)) {  
            $array[] = $array1[$ptr1++];  
        }  
        while ($ptr2 < count($array2)) {  
            $array[] = $array2[$ptr2++];  
        }  
        return;  
    }  
}  
?>

算法原理分析:关键是理解递归调用及其返回函数的原理

原文地址:http://lixiangfeng.com/blog/article/content/13

时间: 2024-10-11 00:57:42

详解四大排序算法的相关文章

(转)详解八大排序算法

概述 排序有内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 我们这里说说八大排序就是内部排序. 当n较大,则应采用时间复杂度为O(nlog2n)的排序方法:快速排序.堆排序或归并排序序. 快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短: 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 将一个记录插入到

ViewPager 详解(二)---详解四大函数

前言:上篇中我们讲解了如何快速实现了一个滑动页面,但问题在于,PageAdapter必须要重写的四个函数,它们都各有什么意义,在上节的函数内部为什么要这么实现,下面我们就结合Android的API说明,详细讲解一下. 相关文章: 1.<ViewPager 详解(一)---基本入门> 2.<ViewPager 详解(二)---详解四大函数> 3.<ViewPager 详解(三)---PagerTabStrip与PagerTitleStrip添加标题栏的异同> 4.<

【机器学习详解】SMO算法剖析(转载)

[机器学习详解]SMO算法剖析 转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/51227754 CSDN?勿在浮沙筑高台 本文力求简化SMO的算法思想,毕竟自己理解有限,无奈还是要拿一堆公式推来推去,但是静下心看完本篇并随手推导,你会迎刃而解的.推荐参看SMO原文中的伪代码. 1.SMO概念 上一篇博客已经详细介绍了SVM原理,为了方便求解,把原始最优化问题转化成了其对偶问题,因为对偶问题是一个凸二次规划问题,这样的凸二次规

详解桶排序以及排序内容大总结(1)

比较器的使用 1) 比较器的实质就是重载比较运算符 2) 比较器可以很好的应用在特殊标准的排序上 3) 比较器可以很好的应用在根据特殊标准排序的结构上 import java.util.Arrays; import java.util.Comparator; import java.util.PriorityQueue; import java.util.TreeSet; public class Code03_Comparator { public static class Student {

JS-排序详解-选择排序

说明 时间复杂度指的是一个算法执行所耗费的时间 空间复杂度指运行完一个程序所需内存的大小 稳定指,如果a=b,a在b的前面,排序后a仍然在b的前面 不稳定指,如果a=b,a在b的前面,排序后可能会交换位置 JS选择排序 原理 首先从原始数组中找到最小的元素,并把该元素放在数组的最前面,然后再从剩下的元素中寻找最小的元素,放在之前最小元素的后面,知道排序完毕. 时间复杂度,空间复杂度,稳定性 平均时间复杂度O(n*n) 最好情况O(n*n) 最差情况O(n*n) 空间复杂度O(1) 稳定性:不稳定

树状数组详解(图形学算法)

目录 一.从图形学算法说起 1.Median Filter 概述 2.r pixel-Median Filter 算法 3.一维模型 4.数据结构的设计 5.树状数组华丽登场 二.细说树状数组 1.树 or 数组? 2.结点的含义 3.求和操作 4.更新操作 5.lowbit函数O(1)实现 6.小结 三.树状数组的经典模型 1.PUIQ模型 2.IUPQ模型 3.逆序模型 4.二分模型 5.再说Median Filter 6.多维树状数组模型 四.树状数组题集整理 一.从图形学算法说起 1.M

【机器学习详解】SMO算法剖析

转载请注明出处:http://blog.csdn.net/luoshixian099/article/details/51227754 CSDN?勿在浮沙筑高台 本文力求简化SMO的算法思想,毕竟自己理解有限,无奈还是要拿一堆公式推来推去,但是静下心看完本篇并随手推导,你会迎刃而解的.推荐参看SMO原文中的伪代码. 1.SMO概念 上一篇博客已经详细介绍了SVM原理,为了方便求解,把原始最优化问题转化成了其对偶问题,因为对偶问题是一个凸二次规划问题,这样的凸二次规划问题具有全局最优解,如下: 其

【机器学习详解】AdaBoost算法原理

转载请注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/51714346 1.概念 AdaBoost是一种级联算法模型,即把几个弱分类器级联到一起去处理同一个分类问题.也就是"三个臭皮匠顶一个诸葛亮"的道理.例如一个专家作出的判定往往没有几个专家一起作出的判定更准确.一种情况:如果每个专家都仅有一票的权利,采用投票机制的方法属于uniform形式:另一种情况是分配给每个专家的票数不一致则属于linear形式.A

iOS疯狂详解之排序(选择排序/插入排序)

选择排序 1.先求最小值 2.找到位置 3.把位置的数放到有序区 4.重复 for (int j = 0; j < count - 1; j++) { int minIndex = j;// 最小值的角标 for (int i = minIndex + 1; i < count; i++) { if (array[minIndex] > array[i]) { minIndex = i; } } if (minIndex != j) { // 优化 无序区的头 不是第一个 // 最小值