引子:javascript实际使用的排序算法在标准中没有定义,可能是冒泡或快排。不用数组原生的 sort() 方法来实现冒泡和快排。

Part 1:冒泡排序(Bubble Sort)

  • 原理:临近的两数两两进行比较,按从小到大或从大到小顺序排列,进行多趟,每一趟过去后(外循环),最大或最小的数字被交换到最后一位(内循环)。
  • 代码:共进行6趟,每一趟比较5次
 var a=[6,2,4,1,5,9],t;
for(var i=0;i<a.length;i++){
for(var j=0;j<a.length-1;j++){
if(a[j]>a[j+1]){
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}

-----分割线----更正于2016.2.25

更正冒泡代码:

  • 代码:共进行5趟(最后一趟即要开始比较的最后一个数不用比较了,它已经被其他趟挤到该在的位置了),每一趟比较5-i次,因为那i次在上一趟中已经排好序了在该在的位置了,肯定是前小后大没什么可比较的了,即后面继续比较无意义。
 var a=[6,2,4,1,5,9],t;
for(var i=0;i<a.length-1;i++){
for(var j=0;j<a.length-1-i;j++){
if(a[j]>a[j+1]){
t=a[j];i
a[j]=a[j+1];
a[j+1]=t;
}
}
}

Part 2:快速排序(Quick Sort)

  • 原理:在一个个数为n的序列中找一个数作为基准数(任意哪个皆可,一般找第一个),即找到该基准数所在位置k,k作为分界点,k左边数均小于基准数,k右边数均大于基准数。
  • 具体做法:设置i,j两个指针分别指向最左端和最右端,每次比较都从j指针开始向左移动寻找比基准数小的数后停止移动,然后指针i向右移动寻找比基准数大的数后停止移动,交换此时i,j所指向的内容,这算一趟中的一次交换完成,直到i,j指针相遇位置即找到k,将基准数和k位置的数字交换,这算完成一趟排序。(解释一下为什么每次一定要从j指针移动开始:举个栗子说明,某序列为[3,1,2,5,4],基准数为3,i指向3,j指向4,如你所愿假设先从i移动找比3大的,i指针移动到5停止,j指针找比3小的,移动到5时相遇了,所以5的位置即为k,交换3和5,序列变为[5,1,2,3,4],这显然越排越乱。之所以一定要从右边开始就是保证了从右边过滤的是比基准数小的,然后再从左边移动时即使相遇了也能保证这个数比基准数小交换后不会影响序列)
  • 分析原理:用分治的思想进行多趟寻找,每一趟都找出基准数所在位置,其中每一趟最坏情况都是两个指针指向了相邻元素,进行交换,这样比较次数和交换次数和冒泡一样了。所以快排在最坏情况下时间复杂度和冒泡一样O(n2)。但快排的平均时间复杂度为O(nlogn),快排之所以比冒泡有优势,在于每次交换都是跳跃式的,不一定每个位置都交换,而且每一趟序列的个数有可能是大于1那样的递减因为k位置不确定划分后才能确定左右两边序列个数,但冒泡每一趟比较序列的个数是规律的每次少一个(n,n-1,n-2...),快排不是像冒泡相邻交换,跳跃式的交换使交换距离变大,因此总的比较和交换次数变少,速度自然就提高。
  • 举例:某序列[6,1,2,7,9,3, 4,5,10,8],说明以下图片均引用自网络(侵删)

以6作为基准数,寻找分界点k。

1.现在i,j指针均已就位

   

2.j指针先从右往左找小于6的数再停下,然后i指针再从左往右找大于6的数再停下,最后交换

3.第一趟的第一次交换完毕,序列变为[6,1,2,5,9,3,4,7,10,8]

4.j指针继续向左寻找小于6的元素,i指针继续向右寻找大于6的元素,最后交换

5.第一趟的第二次交换完毕,序列变为[6,1,2,5,4,3,9,7,10,8]

6.j指针继续向左寻找小于6的元素,i指针继续向右寻找大于6的元素,到3时相遇停止移动,即找到位置k

7.交换3和6,第一趟排序完毕。序列变为[3,1,2,5,4,6,9,7,10,8]

8.剩下的就每一趟都是按此方式重排,可用分治的思想解决,先解决6左边的序列,完毕后再解决6右边序列,直到不可拆分出新的子序列为止

  • 代码:为了测试代码差点把浏览器搞崩,一不小心少了某个条件就进入死递归了。。。

     function quicksort(a,left,right){
    if(left>right){ //一定要有这个判断,因为有递归left和i-1,若没有这个判断条件,该函数会进入无限死错位递归
    return;
    } var i=left,
    j=right,
    jizhun=a[left]; //基准总是取序列开头的元素 while(i!=j){ //该while的功能为每一趟进行的多次比较和交换最终找到位置k。当i==j时意味着找到k位置了
    while(a[j]>=jizhun&&i<j){j--} //只要大于等于基准数,j指针向左移动直到小于基准数才不进入该while。i<j的限制条件也是很重要,不然一直在i!=j这个循环里,j也会越界
    while(a[i]<=jizhun&&i<j){i++} //只要小于等于基准数,i指针向右移动直到大于基准数才不进入该while。等于条件也是必要的,举例[4,7,6,4,3]验证一下是两个4交换
    if(i<j){ //如果i==j跳出外层while
    t=a[i];
    a[i]=a[j];
    a[j]=t
    }
    } a[left]=a[i];//交换基准数和k位置上的数
    a[i]=jizhun; quicksort(a,left,i-1);
    quicksort(a,i+1,right);
    } var array=[4,7,2,8,3,9,12];
    quicksort(array,0,array.length-1);//排完序后再看array是[2, 3, 4, 7, 8, 9, 12]

性能测试:在jsperf整了个链接测试一下冒泡,快排,sort()对100个数字排序的性能,http://jsperf.com/sortdemo  果然还是sort()原生方法快。

在chrome控制台统计代码执行的时间,也同样验证了sort()原生方法快:

参考:http://developer.51cto.com/art/201403/430986.htm

冒泡,快排算法之javascript初体验的更多相关文章

  1. 快排算法Java版-每次以最左边的值为基准值手写QuickSort

    如题 手写一份快排算法. 注意, 两边双向找值的时候, 先从最右边起找严格小于基准值的值,再从最左边查找严格大于基准base的值; 并且先右后左的顺序不能反!!这个bug改了好久,233~ https ...

  2. 【算法】桶排->冒泡->快排

    啊哈 算法 http://pan.baidu.com/s/1jGGl2SI http://pan.baidu.com/s/15C1oq 1 节 最快最简单的排序——桶排序 在我们生活的这个世界中到处都 ...

  3. Java写 插入 选择 冒泡 快排

    /** * Created by wushuang on 2014/11/19. */ public class SortTest { @Test public void mainTest() { i ...

  4. python快排算法

    通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列. ...

  5. 快排算法(C++版)

    #include <iostream> using namespace std; /** Quick Sort * * split: cmp && swap * left ...

  6. oc 快排算法

    直接复制粘贴就可以用了 - (void)viewDidLoad { [super viewDidLoad]; NSMutableArray *M_arr = [[NSMutableArray allo ...

  7. javascript初体验(一)

    数据类型 数字 (Number),整数或浮点数,例如42或3.14159 字符串 (String) 布尔值 (Boolean) null (js大小写敏感,因此null和NULL不一样) undefi ...

  8. 快排 - 快速排序算法 (Chinar出品 简单易懂)

    Quicksort 快排的简单讲解 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  9. scala写算法-快排

    快排算法很经典,今天用scala的函数式思维来整理一下并实现: def qsort(list: List[Int]):List[Int]=list match { case Nil=>Nil c ...

随机推荐

  1. FluorineFx 播放FLV 时堆棧溢出解决 FluorineFx NetStream.play 并发时,无法全部连接成功的解决办法

    http://25swf.blogbus.com/tag/FluorineFx/ http://www.doc88.com/p-7002019966618.html  基于Red5的视频监控系统的研究 ...

  2. MVC4数据注释与验证

    Using Validation Annotations Required必须项验证属性 [Required] public string FirstName { get; set; } [Requi ...

  3. highcharts笔记 highcharts学习 highcharts用法

    标示线:plotLines : 绘制线:

  4. Working with MTD Devices

    转:http://www.linuxforu.com/2012/01/working-with-mtd-devices/ Working with MTD Devices By Mohan Lal J ...

  5. Java项目经验——程序员成长的关键(转载)

    Java就是用来做项目的!Java的主要应用领域就是企业级的项目开发!要想从事企业级的项目开发,你必须掌握如下要点:1.掌握项目开发的基本步骤2.具备极强的面向对象的分析与设计技巧3.掌握用例驱动.以 ...

  6. Xcode代码格式化教程,可自定义样式

    来源:iOS_小松哥 链接:http://www.jianshu.com/p/a725e24d7835 为什么要格式化代码 当团队内有多人开发的时候,每个人写的代码格式都有自己的喜好,也可能会忙着写代 ...

  7. BootStrap2学习日记16---选项卡内容

    代码: <ul class="nav nav-tabs"> <li class="active"><a href="#t ...

  8. [Java] 模拟HTTP的Get和Post请求

    在之前,写了篇Java模拟HTTP的Get和Post请求的文章,这篇文章起源与和一个朋友砍飞信诈骗网站的问题,于是动用了Apache的comments-net包,也实现了get和post的http请求 ...

  9. 【Shell脚本学习17】Shell case esac语句

    case ... esac 与其他语言中的 switch ... case 语句类似,是一种多分枝选择结构. case 语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令.case语句格式如下: ...

  10. LocalActivityManager的内部机制

    LocalActivityManager内部机制的核心在于,它使用了主线程对象mActivityThread来装载指定的Activity.注意,这里是装载,而不是启动,这点很重要. 所谓的启动,一般是 ...