关于排序算法的博客何止千千万了,也不多一个轮子,那我就斗胆粗制滥造个轮子吧!下面的排序算法未作说明默认是从小到大排序。

1.快速排序

为什么把快排放在最前面呢,因为传说Chrome中数组的sort方法默认采用的就是快排。

算法思想:

(1)在数据集之中,选择一个元素作为"基准"(pivot)。

(2)所有小于"基准"的元素,都移到"基准"的左边;所有大于"基准"的元素,都移到"基准"的右边。

(3)对"基准"左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

毋庸置疑,快排的实现离不开递归了。下面奉上阮大神关于快排的博客一篇。

快速排序(Quicksort)的Javascript实现

在阮大神的博客里有一个真心一目了然的实现方法,下面直接粘上算法实现并添加注释,如果不能理解可以点击上面的链接,直接查看阮大神的博客,如果阮大神的博客都看不懂,请关闭浏览器回炉再造!!!!

  1. var quickSort=function(arr){
  2. if (arr.length<=1) {//如果数组长度小于等于1,直接返回给数组
  3. return arr;
  4. }
  5. /*选择"基准"(pivot),并将其与原数组分离,再定义两个空数组,用来存放一左一右的两个子集。*/
  6. var pivotIndex=Math.floor(arr.length/2);
  7. //基准值可以任意选择,但是选择中间的值比较容易理解
  8. var pivot=arr.splice(pivotIndex,1)[0];
  9. var left=[];
  10. var right=[];
  11. /*然后,开始遍历数组,小于"基准"的元素放入左边的子集,大于基准的元素放入右边的子集。*/
  12. for (var i = 0; i < arr.length; i++) {
  13. if (arr[i]<pivot) {
  14. left.push(arr[i]);
  15. }else{
  16. right.push(arr[i]);
  17. }
  18. }
  19. //最后,将各个部分连接成整体
  20. return quickSort(left).concat([pivot],quickSort(right));
  21. };
  22. var arr=[85,24,63,45,17,31,96,50];
  23. console.log(quickSort(arr));

简直没有比这段代码更能直接明了的表达快排的思想了。但是阮大神的方法牺牲空间换时间方法,查看了很多的算法书,里面的实现方法都是直接在原来的数组上进行交换操作的。下面给出了《学习JavaScript数据结构与算法》中的实现方法,国内比较出名的算法书《大话数据结构》《算法-第四版》中给出的示例也是大同小异。

  1. var quickSort=function (arr) {
  2. quick(arr,0,arr.length-1);//传索引0和及其最末位置,因为要排整个数组
  3. return arr;
  4. }
  5. /*实施快排*/
  6. var quick=function(arr,left,right){
  7. var index;
  8. if (arr.length>1) {
  9. index=partition(arr,left,right);//获取划分后的基准位置
  10. if (left<index-1) {
  11. quick(arr,left,index-1);//对左部分再进行快排
  12. }
  13. if (index<right) {//对右部分再进行快排
  14. quick(arr,index,right);
  15. }
  16. }
  17. }
  18. /*实施划分,并返回划分后的基准位置*/
  19. var partition=function(arr,left,right){
  20. var pivot=arr[Math.floor((right+left)/2)],
  21. i=left,j=right;
  22. while(i<j){
  23. while(arr[i]<pivot){
  24. i++;
  25. }
  26. while(arr[j]>pivot){
  27. j--;
  28. }
  29. if(i<=j){
  30. swapQuickSort(arr,i,j);
  31. i++;j--;
  32. }
  33. }
  34. return i;
  35. }
  36. /*交换数组的两个元素*/
  37. var swapQuickSort=function(array,index1,index2){
  38. var temp=array[index1];
  39. array[index1]=array[index2];
  40. array[index2]=temp;
  41. };
  42. var arr=[85,24,63,45,17,31,96,50];
  43. console.log(quickSort(arr));

快速排序有两个方向,当arr[i] <= pivot,左边的i下标一直往右走,当arr[j] > pivot,右边的j下标一直往左走,。如果i和j都走不动了,i <= j, 交换arr[i]和arr[j],重复上面的过程,直到i>=j,完成一趟快速排序。交换的时候,很有可能把元素的稳定性打乱,比如序列为 5 3 3 4, 现在基准是第二个元素3,就会把前一个3和后一个3交换,元素3的稳定性被打乱,所以快速排序是一个不稳定的排序算法。


2.归并排序

算法思想:

归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。

归并排序其实要做两件事:

(1)“分解”——将序列每次折半划分。

(2)“合并”——将划分后的序列段两两合并后排序。

  1. var mergeSort=function (arr) {
  2. if (arr.length<=1) {
  3. return arr;
  4. }
  5. var mid=Math.floor(arr.length/2),
  6. //分解序列
  7. left=arr.slice(0,mid),
  8. right=arr.slice(mid,arr.length);
  9. return merge(mergeSort(left),mergeSort(right));
  10. }
  11. var merge=function(left,right){//合并有序序列
  12. var result=[],i=0,j=0;
  13. while(i<left.length&&j<right.length){
  14. if (left[i]<right[j]) {
  15. result.push(left[i++]);
  16. }else{
  17. result.push(right[j++]);
  18. }
  19. }
  20. while(i<left.length){
  21. result.push(left[i++]);
  22. }
  23. while(j<right.length){
  24. result.push(right[j++]);
  25. }
  26. return result;
  27. }
  28. var arr=[85,24,63,45,17,31,96,50];
  29. console.log(mergeSort(arr));

归并排序是把序列递归地分成短序列,递归出口是短序列只有1个元素(认为直接有序)或者2个序列(1次比较和交换),然后把各个有序的段序列合并成一个有 序的长序列,不断合并直到原序列全部排好序。可以发现,在1个或2个元素时,1个元素不会交换,2个元素如果大小相等也没有人故意交换,这不会破坏稳定 性。那么,在短的有序序列合并的过程中,稳定是是否受到破坏?没有,合并过程中我们可以保证如果两个当前元素相等时,我们把处在前面的序列的元素保存在结 果序列的前面,这样就保证了稳定性。所以,归并排序也是稳定的排序算法。

前面介绍的快速排序和归并排序被大多数语言作为排序的默认实现。下面介绍几种经典的排序算法。


3.冒泡排序

基本思想:

从左到右依次比较相邻的两项,如果前一项比后一项大就交换,这样一趟冒泡下来,最大项就会移动到最右端,重复前面的步骤,依次得到次大项…,

实现要点:双层循环,内层交换

  1. var bubbleSort=function (arr) {
  2. var length=arr.length;
  3. for (var i = 0; i < length; i++) {
  4. /*因为每冒泡一次就会将本次最大值放在最后,所以后面的就不需要再比较了,
  5. 所以可以从内循环减去外循环已经跑过的轮数*/
  6. for (var j = 0; j <length-1-i; j++) {
  7. if (arr[j]>arr[j+1]) {
  8. var temp=arr[j];
  9. arr[j]=arr[j+1];
  10. arr[j+1]=temp;
  11. }
  12. }
  13. }
  14. return arr;
  15. }
  16. var arr=[85,24,63,45,17,31,96,50];
  17. console.log(bubbleSort(arr));

冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。所以,如果两个元素相等,我想你是不会再无 聊地把他们俩交换一下的;如果两个相等的元素没有相邻,那么即使通过前面的两两交换把两个相邻起来,这时候也不会交换,所以相同元素的前后顺序并没有改 变,所以冒泡排序是一种稳定排序算法。


4.选择排序(简单选择排序)

算法思想:

简单选择排序是一种原址比较排序算法,选择排序大致的思路是找到序列中最小值与第一个元素交换,接着找到次小值与第二个元素交换,以此类推。

实现要点:双层循环,使用一个变量存储最小值下标

  1. var selectionSort=function (arr) {
  2. var length=arr.length;
  3. for (var i = 0; i < length; i++) {
  4. var min=i;//用一个变量存储最小值下标,初始值为仍未排序的第一个元素的下标
  5. for (var j = i+1; j <length; j++) {
  6. //与当前最小值比较,如果小于当前最小值,最小值下标就要移动了
  7. if (arr[j]<arr[min]) {
  8. min=j;
  9. }
  10. }
  11. if(min!=i){//如果最小值下标移动了,就交换元素
  12. var temp=arr[i];
  13. arr[i]=arr[min];
  14. arr[min]=temp;
  15. }
  16. }
  17. return arr;
  18. }
  19. var arr=[85,24,63,45,17,31,96,50];
  20. console.log(selectionSort(arr));

选择排序是给每个位置选择当前元素最小的,比如给第一个位置选择最小的,在剩余元素里面给第二个元素选择第二小的,依次类推,直到第n-1个元素,第n个 元素不用选择了,因为只剩下它一个最大的元素了。举个例子,序列5 8 5 2 9, 我们知道第一遍选择第1个元素5会和2交换,那么原序列中2个5的相对前后顺序就被破坏了,所以选择排序不是一个稳定的排序算法。


5.插入排序(直接插入排序)

算法思想:

将一个记录插入到已排序好的有序表中,从而得到一个新,记录数增1的有序表。即:先将序列的第1个记录看成是一个有序的子序列,然后从第2个记录逐个进行插入,直至整个序列有序为止。

  1. var insertionSort=function (arr) {
  2. var length=arr.length;
  3. for (var i = 1; i < length; i++) {
  4. var temp=arr[i];//待插入元素
  5. var j=i;
  6. while (j>0&&temp<arr[j-1]) {//从已有序的序列最后一个元素开始往前比较
  7. arr[j]=arr[j-1];//如果不符合插入要求,那么与之比较的元素就要后移
  8. j--;
  9. }
  10. arr[j]=temp;//插入元素到合适位置
  11. }
  12. return arr;
  13. }
  14. var arr=[85,24,63,45,17,31,96,50];
  15. console.log(insertionSort(arr));

插入排序是在一个已经有序的小序列的基础上,一次插入一个元素。当然,刚开始这个有序的小序列只有1个元素,就是第一个元素。比较是从有序序列的末尾开 始,也就是想要插入的元素和已经有序的最大者开始比起,如果比它大则直接插入在其后面,否则一直往前找直到找到它该插入的位置。如果碰见一个和插入元素相 等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后顺序没有改变,从原无序序列出去的顺序就是排好序后的顺序,所以插入排序是稳 定的。


6.希尔排序

前面介绍的直接插入排序在待排序元素少或者序列基本有序时很高效,但是一般情况下,上面两个条件很难满足,但是通过将序列分组可以减少每次参与排序的元素数量。希尔排序就是这样一种改进算法。

算法思想:

对待排记录序列先作“宏观”调整,再作“微观”调整。所谓“宏观”调整,指的是“跳跃式”的插入排序。即:将记录序列分成若干子序列,每个子序列分别进行直接插入排序。关键是这种子序列不是由相邻的记录构成的。假设将 n 个记录分成 d 个子序列,则这 d 个子序列分别为:

{ R[1],R[1+d],R[1+2d],…,R[1+kd] }

{ R[2],R[2+d],R[2+2d],…,R[2+kd] }… { R[d],R[2d],R[3d],…,R[kd],R[(k+1)d] }

  1. var shellSort=function (arr) {
  2. var length=arr.length;
  3. var gap=Math.floor(length/2);
  4. while(gap>=1){
  5. for (var i = gap; i < length; i++) {
  6. var j=i;
  7. var temp=arr[i];
  8. /*对距离为gap的元素组内进行直接插入排序
  9. 下面这段是不是似曾相识,和直接排序算法如出一辙。
  10. 这不过直接排序算法的gap为1*/
  11. while(j >=0&&temp<arr[j-gap]) {
  12. arr[j]=arr[j-gap];//元素在本组内后移
  13. j-=gap;
  14. }
  15. arr[j]=temp;
  16. }
  17. gap=Math.floor(gap/2);
  18. }
  19. return arr;
  20. }
  21. var arr=[85,24,63,45,17,31,96,50,23];
  22. console.log(shellSort(arr));

希尔排序是按照不同步长对元素进行插入排序,当刚开始元素很无序的时候,步长最大,所以插入排序的元素个数很少,速度很快;当元素基本有序了,步长很小, 插入排序对于有序的序列效率很高。所以,希尔排序的时间复杂度会比o(n^2)好一些。由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元 素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以希尔排序是不稳定的。


八大排序算法还有两种:基数排序和堆排序,平时用的比较少,这里就没介绍了·····好吧,我承认是我偷懒。



下面总结一下其他相关知识点:

  • 不稳定的排序算法:选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,
  • 稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
Algorithm Average Best Worst extra space stable
冒泡排序 O(N^2) O(N) O(N^2) O(1) 稳定
直接插入排序 O(N^2) O(N) O(N^2) O(1) 稳定
希尔排序 O(NlogN)~O(N^2) O(N^13) O(N^2) O(1) 不稳定
简单选择排序 O(N^2) O(N^2) O(N^2) O(1) 不稳定
快速排序 O(NlogN) O(NlogN) O(N^2) O(logN)~O(N^2) 不稳定
归并排序 O(NlogN) O(NlogN) O(NlogN) O(N) 稳定
堆排序 O(NlogN) O(NlogN) O(NlogN) O(1) 不稳定
基数排序 O(d*(N+K)) O(d*(N+K)) O(d*(N+K)) O(N+K) 稳定

为了证明其实我并不懒,结尾还是送一个彩蛋吧,既然已经介绍了排序,增能不顺带讲讲经典的二分查找算法实现。

二分查找

不要忘了二分查找的前提是序列有序。可以选用前面已经介绍的任何一种排序算法,这里就选择快速排序吧。

算法步骤:

(1)选择序列的中间值。

(2)如果选中值就是待搜索值,那么你已经点到秋香了

(3)如果待搜索值比选中值小,则返回步骤1并在选中值左边的子序列中寻找

(4)如果待搜索值比选中值大,则返回步骤1并在选中值右边的子序列中寻找

  1. var binarySearch=function(arr,item){
  2. arr=quickSort(arr);//先对序列排序
  3. var low=0,
  4. high=arr.length-1,
  5. mid;
  6. while(low<=high){
  7. mid=Math.floor((high+low)/2);
  8. if (arr[mid]<item) {
  9. low=mid+1;
  10. }else if (arr[mid]>item) {
  11. high=mid-1;
  12. }else{
  13. return mid;
  14. }
  15. }
  16. return -1;//没有找到就返回-1
  17. };
  18. var arr=[85,24,63,45,17,31,96,50,23];
  19. console.log(binarySearch(arr,45));

参考:

JS实现常用排序算法—经典的轮子值得再造的更多相关文章

  1. js 前端常用排序算法总结

    (冒泡排序.快排顺序.选择排序.插入排序.归并排序) 下面是前端比较常用的五个算法demo: 冒泡算法:比较两个相邻的数值,if第一个>第二个,交换他们的位置元素项向上移动至正确的顺序. fun ...

  2. Java数据结构和算法(三):常用排序算法与经典题型

    常用的八种排序算法 1.直接插入排序 我们经常会到这样一类排序问题:把新的数据插入到已经排好的数据列中.将第一个数和第二个数排序,然后构成一个有序序列将第三个数插入进去,构成一个新的有序序列.对第四个 ...

  3. 常用排序算法的python实现和性能分析

    常用排序算法的python实现和性能分析 一年一度的换工作高峰又到了,HR大概每天都塞几份简历过来,基本上一天安排两个面试的话,当天就只能加班干活了.趁着面试别人的机会,自己也把一些基础算法和一些面试 ...

  4. 常用排序算法java实现

    写在前面:纸上得来终觉浅.基本排序算法的思想,可能很多人都说的头头是到,但能说和能写出来,真的还是有很大区别的. 今天整理了一下各种常用排序算法,当然还不全,后面会继续补充.代码中可能有累赘或错误的地 ...

  5. 第四百一十五节,python常用排序算法学习

    第四百一十五节,python常用排序算法学习 常用排序 名称 复杂度 说明 备注 冒泡排序Bubble Sort O(N*N) 将待排序的元素看作是竖着排列的“气泡”,较小的元素比较轻,从而要往上浮 ...

  6. javascript常用排序算法实现

    毕业后,由于工作中很少需要自已去写一些排序,所以那些排序算法都忘得差不多了,不过排序是最基础的算法,还是不能落下啦,于是找了一些资料,然后用Javascript实现了一些常用的算法,具体代码如下: & ...

  7. Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 本文由网络资料整理转载而来,如有问题,欢迎指正! 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排 ...

  8. 转载部长一篇大作:常用排序算法之JavaScript实现

    转载部长一篇大作:常用排序算法之JavaScript实现 注:本文是转载实验室同门王部长的大作,找实习找工作在即,本文颇有用处!原文出处:http://www.cnblogs.com/ywang172 ...

  9. Java 常用排序算法/程序员必须掌握的 8大排序算法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配 ...

随机推荐

  1. List接口方法使用(PS:Java 编程思想阅读小结)

    1.用代码说话 package JavaProject; import java.util.*; public class A{ public static void main(String[]arg ...

  2. jdk 安装 环境变量配置

    右键选择 计算机→属性→高级系统设置→高级→环境变量 1.系统变量→新建 变量名:JAVA_HOME 变量值:(变量值填写你的jdk的安装目录,例如本人是 C:\Program Files\Java\ ...

  3. sublime 安装插件GitGutter报错,git binary cannot be found等等

    今天给sublime text安装插件GitGutter的时候,居然报错了,网上查找了下解决方法,在此记录下.因为本博主的电脑是windows的,所以这里只能提供windows的方法啦. 解决方法很简 ...

  4. nginx安装与配置

    一.在线安装 ubuntu 安装 sudo apt-get install nginx 安装后文件结构为: 配置文件:/etc/nginx ,并且每台虚拟主机已经安排在 /etc/nginx/site ...

  5. Oracle 中 decode 函数用法

    Oracle 中 decode 函数用法 含义解释:decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下:IF 条件=值1 THEN RETURN(翻译 ...

  6. php、前端开发(网站建设)环境搭建

    php集成开发环境wampserver,是一款免费开源的软件,下载地址http://www.wampserver.com,由于是国外的网站,打开速度慢,根据自己的电脑选择32位/64位的系统下载.

  7. 判断字符串是否相等 isEqualToString:

    // if((btn.currentTitle == answerBtn.currentTitle) && btn.hidden == YES) // 字符串相等比较 不要直接比,这样 ...

  8. mysql怎么查询一条记录的前一条记录和后一条记录

    上一条:select * from 表 where 数据id<@当前显示数据id order by 数据_id asc) limit 1下一条:select * from 表 where 数据i ...

  9. composer 报错:Your requirements could not be resolved to an installable set of packages 解决方法

    composer 报错: - Your requirements could not be resolved to an installable set of packages xxxxxxxxxxx ...

  10. MongoDB安装

    安装 1>设置MongoDB目录 cd /home/apps      附:centOS下创建目录命令  mkdir /home/apps 2>下载mongodb curl -O http ...