javascript常用经典算法详解


Posted in Javascript onJanuary 11, 2017

阅读目录

  • 冒泡排序
  • 插入排序
  • 希尔排序
  • 归并排序
  • 快速排序
  • 选择排序
  • 奇偶排序

总结

前言:在前端大全中看到这句话,以此共勉。基础决定你可能达到的高度, 而业务决定了你的最低瓶颈

其实javascript算法在平时的编码中用处不大,不过不妨碍我们学习它,学习一下这些算法的思想,锻炼一下自己的思维模式。

本文不会每种方法都介绍一下,只介绍一下七种,纯属为了学习而学习,如果觉得代码不是很好理解,可以将数组里面的内容代入函数里面。

不过刚开始理解的时候确实挺头疼的。废话少说,搞起来!!

冒泡排序

原理:

从第一个元素开始,往后比较,遇到比自己小的元素就交换位置

javascript常用经典算法详解

(来源于百度图片)

特点:

交换的次数最多,所以它的性能是最差的

代码实现:

function bubbleSort(arr){
 var len=arr.length;
 for(var i=0;i<len;i++){
 for(var j=0;j<len-1-i;j++){ 
  if(arr[j]>arr[j+1]){ //相邻元素两两对比
  var temp=arr[j+1]; //交互位置,所以大的都放到了最后面
  arr[j+1]=arr[j];
  arr[j]=temp;

  }
 }
 }
 return arr;
}
var arr=[2,3,6,4,2,1,90,100,20,5];
console.log(bubbleSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]

插入排序

原理:

插入排序的基本操作就是将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据

如图所示

javascript常用经典算法详解

在插入排序中,数组会被划分为两种,“有序数组块”和“无序数组块”,

   第一遍的时候从”无序数组块“中提取一个数20作为有序数组块。

   第二遍的时候从”无序数组块“中提取一个数60有序的放到”有序数组块中“,也就是20,60。

   第三遍的时候同理,不同的是发现10比有序数组的值都小,因此20,60位置后移,腾出一个位置让10插入。

   然后按照这种规律就可以全部插入完毕。

下面是一张gif图

javascript常用经典算法详解

特点:

插入算法把要排序的数组分成两部分:

第一部分包含了这个数组的所有元素,但将第一个元素除外(让数组多一个空间才有插入的位置).

第二部分就只包含这一个元素(即待插入元素)。在第一部分排序完成后,再将这个最后元素插入到已排好序的第一部分中

比冒泡排序快一点

代码实现:

//插入排序
//假定当前元素之前的元素已经排好序,先把自己的位置空出来,
//然后前面比自己大的元素依次向后移,直到空出一个"坑",
//然后把目标元素插入"坑"中
function insertSort(arr){
 // 从第二个元素开始,因为要留出一个坑
 for(var i=1;i<arr.length;i++){
 var x=arr[i]; 
 for(var j=i-1;arr[j]>x;j--){ //后挪空出位置 .
  arr[j+1]=arr[j];
 }
 if(arr[j+1]!=x){
  arr[j+1]=x;
 }
 }
 return arr;
}
var arr=[2,3,6,4,2,1,90,100,20,5];
console.log(insertSort(arr,2)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]

希尔排序

原理:

希尔排序也叫 递减增量排序算法,是插入排序的一种神龟进化版。

什么叫递减增量呢,就是定义一个间隔序列,例如是5,3,1。第一次处理,会处理所有间隔为5的,

下一次会处理间隔为3的,最后一次处理间隔为1的元素。也就是相邻元素执行标准插入排序。

 步骤如下:

    1、先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。

    2、所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序。

    3、取第二个增量d2<d1重复上述的分组和排序,

    4、直至所取的增量dt=1(dt<dt-l<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

javascript常用经典算法详解

这里增量的取法如下:

    第一次增量的取法为: d=count/2;

    第二次增量的取法为:  d=(count/2)/2;

    最后一直到: d=1;

看上图观测的现象为:

    d=3时:将40跟50比,因50大,不交换。

                 将20跟30比,因30大,不交换。

                 将80跟60比,因60小,交换。

    d=2时:将40跟60比,不交换,拿60跟30比交换,此时交换后的30又比前面的40小,又要将40和30交换,如上图。

                 将20跟50比,不交换,继续将50跟80比,不交换。

    d=1时:这时就是前面讲的插入排序了,不过此时的序列已经差不多有序了,所以给插入排序带来了很大的性能提高。

特点:

 由于多次插入排序,我们知道一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,

  相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱,所以shell排序是不稳定的。

 打个比方,我原来的数组是[5,4,3,2,1]的,这样一打乱就全部重新排了。

代码实现:

function shellSort(arr){
 var gap=Math.floor(arr.length/2);
 while(gap>0){
 for(var i=gap;i<arr.length;i++){
  temp=arr[i];
  for(var j=i;j>=gap&&arr[j-gap]>temp;j-=gap){
  arr[j]=arr[j-gap];
  }
  arr[j]=temp;
 }
 gap=Math.floor(gap/2);
 }
 return arr;
}
var arr = [2,3,6,4,2,1,90,100,20,5];
console.log(shellSort(arr)); //[1, 2, 2, 3, 4, 5, 6, 20, 90, 100]

归并排序

原理:

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

有以下几个步骤:

  1、把长度为n的输入序列分成两个长度为n/2的子序列;

  2、对这两个子序列继续分为m/2的子序列,一直分下去

  3、将两个排序好的子序列合并成一个最终的排序序列。

javascript常用经典算法详解

再来一张静态图,比较好理解

javascript常用经典算法详解

这里需要补充是,归并中对数组的分割是从上往下的,归并中数组的比较是从下往上的。

特点:

速度仅次于快速排序,为稳定排序算法,一般用于对总体无序,但是各子项相对有序的数列.

属于分治思想,递归归并

代码实现:

/* 排序并合并*/
function merge(left, right) {
 var re = [];
 while(left.length > 0 && right.length > 0) {
 if(left[0] < right[0]) {


// 如果左边的数据小于右边的数据,将左边的数据取出,放到新数组那里
  re.push(left.shift());
 } else {
  re.push(right.shift());
 }
 }
 /* 当左右数组长度不等.将比较完后剩下的数组项链接起来即可 */
 return re.concat(left).concat(right);
}
function mergeSort(arr) {
 if(arr.length == 1){
 return arr;
 }
 /* 首先将无序数组划分为两个数组 */
 var mid = Math.floor(arr.length / 2);
 var left = arr.slice(0, mid);
 var right = arr.slice(mid);
 /* 递归分别对左右两部分数组进行排序合并 */
 return merge(mergeSort(left), mergeSort(right));
}
var arr=[2,3,6,4,2,1,90,100,20,5];
console.log(mergeSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]

快速排序

原理:

1、在数据集之中,选择一个元素作为"基准"(pivot)。比如选择下面数字45

javascript常用经典算法详解

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

javascript常用经典算法详解

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

javascript常用经典算法详解

特点:速度最快。和归并排序不同的是,归并排序是先分为两组再继续排,而快速排序是边分边排

代码实现:

// 大致分三步:
 // 1、找基准(一般是以中间项为基准)
 // 2、遍历数组,小于基准的放在left,大于基准的放在right
 // 3、递归
 function quickSort(arr){
 //如果数组<=1,则直接返回
 if(arr.length<=1){
  return arr;
 }
 var pivotIndex=Math.floor(arr.length/2);
 //找基准,并把基准从原数组删除
 var pivot=arr.splice(pivotIndex,1)[0];
 //定义左右数组
 var left=[];
 var right=[];

 //比基准小的放在left,比基准大的放在right
 for(var i=0;i<arr.length;i++){
  if(arr[i]<=pivot){
  left.push(arr[i]);
  }else{
  right.push(arr[i]);
  }
 }
 //递归
 return quickSort(left).concat([pivot],quickSort(right));
 }
 var arr=[2,3,6,4,2,1,90,100,20,5];
 console.log(quickSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]

选择排序

原理:在要排序的一组数中,选出最小的一个数与第一个位置的数交换,然后剩下的数当中找出最小的与第二个位置的数交换,如此循环直到倒数第二个数和最后一个数为止。

javascript常用经典算法详解

静态图:

javascript常用经典算法详解

特点:可以说是冒泡排序的衍生品,效率比较一般般

代码实现:

// 在无序区中选出最小的元素,然后将它和无序区的第一个元素交换位置。
function selectSort(arr){
 length = arr.length;
 for (var i = 0; i < length; i++){ // 循环数组
 var _min = arr[i]; // 把每一次的 数组里面的数字记录下来
 var k = i;   // 记录下来索引
 for (var j = i + 1; j < length; j++){ // 当前的数字与后一个数字相比较
  if (_min > arr[j]){ //当前的数 大于 后面一个数的话
  _min = arr[j]; // 就讲后面 的数值 保存下来
  k = j;  /// 保存索引
  }
 }
 arr[k] = arr[i]; // 进行交换位置
 arr[i] = _min;
 }
 return arr;
}
var arr=[2,3,6,4,2,1,90,100,20,5];
console.log(selectSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]

奇偶排序

原理:

选取所有奇数列的元素与其右侧相邻的元素进行比较,将较小的元素排序在前面;

选取所有偶数列的元素与其右侧相邻的元素进行比较,将较小的元素排序在前面;

重复前面两步,直到所有序列有序为止。

如下图所示:

javascript常用经典算法详解

gif图:

javascript常用经典算法详解

特点:奇数和偶数序列交替比较

代码实现:

function oddEvenSort(arr){
 //swaped用来控制循环是否要继续,如果左边的都比右边的小,则退出循环,返回排好的数组
 var swaped=true; 
 var k=0;
 while(swaped){
 if(k>0){
  swaped=false; 
 }
 for(var i=k;i<arr.length-1;i+=2){
  if(arr[i]>arr[i+1]){
  // 如果左边的数字比右边的大,两者交换位置
  arr[i]=[ arr[i+1], arr[i+1]=arr[i] ][0]; 
  swaped=true;
  }
 }
 k=[1,0][k]; //奇数和偶数之间的转行
 }
 return arr;
} 
var arr=[2,3,6,4,2,1,90,100,20,5];
console.log(oddEvenSort(arr)); // [1, 2, 2, 3, 4, 5, 6, 20, 90, 100]

总结

本文只是总结了算法中的一部分,算法的精髓就在于他们的思想,在js中用处应该不是很大。如果第一遍看不太懂那些代码,可以试着自己敲一遍,我在总结的时候,遇到理解不了的代码,自己敲完理解程度就会加深一些。

理解完,确实这些算法的实现思想博大精深,不得不感慨一下前辈们思想的深度。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
js 小数取整的函数
May 10 Javascript
Javascript 倒计时源代码.(时.分.秒) 详细注释版
May 09 Javascript
Javascript图片上传前的本地预览实例
Jun 16 Javascript
js实现右下角提示框的方法
Feb 03 Javascript
JavaScript对Cookie进行读写操作实例
Jul 25 Javascript
利用jquery给指定的table动态添加一行、删除一行的方法
Oct 12 Javascript
深入理解Node.js中通用基础设计模式
Sep 19 Javascript
node.js中axios使用心得总结
Nov 29 Javascript
使用VueRouter的addRoutes方法实现动态添加用户的权限路由
Jun 03 Javascript
jQuery鼠标滑过横向时间轴样式(代码详解)
Nov 01 jQuery
vue中重定向redirect:‘/index‘,不显示问题、跳转出错的完美解决
Sep 28 Javascript
关于uniApp editor微信滑动问题
Jan 15 Javascript
总结几道关于Node.js的面试问题
Jan 11 #Javascript
微信端开发--登录小程序步骤
Jan 11 #Javascript
Vue数据驱动模拟实现1
Jan 11 #Javascript
利用iscroll4实现轮播图效果实例代码
Jan 11 #Javascript
详解js前端代码异常监控
Jan 11 #Javascript
Vue数据驱动模拟实现3
Jan 11 #Javascript
jQuery实现判断控件是否显示的方法
Jan 11 #Javascript
You might like
PHP缓存机制Output Control详解
2014/07/14 PHP
mac下多个php版本快速切换的方法
2016/10/09 PHP
thinkPHP5.0框架自动加载机制分析
2017/03/18 PHP
yii2.0整合阿里云oss的示例代码
2017/09/19 PHP
Yii2.0框架模型多表关联查询示例
2019/07/18 PHP
javascript实现仿银行密码输入框效果的代码
2007/12/13 Javascript
jQuery.fn和jQuery.prototype区别介绍
2013/10/05 Javascript
JQuery中$.each 和$(selector).each()的区别详解
2015/03/13 Javascript
AngularJS 与百度地图的结合实例
2016/10/20 Javascript
Vue.js仿微信聊天窗口展示组件功能
2017/08/11 Javascript
vue router下的html5 history在iis服务器上的设置方法
2017/10/18 Javascript
详解vue2.0监听属性的使用心得及搭配计算属性的使用
2018/07/18 Javascript
three.js实现炫酷的全景3D重力感应
2018/12/30 Javascript
JS如何定义用字符串拼接的变量
2020/07/11 Javascript
Vue 数据绑定的原理分析
2020/11/16 Javascript
详解python调度框架APScheduler使用
2017/03/28 Python
windows下python安装paramiko模块和pycrypto模块(简单三步)
2017/07/06 Python
Python遍历pandas数据方法总结
2018/02/09 Python
python实现逆序输出一个数字的示例讲解
2018/06/25 Python
在交互式环境中执行Python程序过程详解
2019/07/12 Python
Python filter()及reduce()函数使用方法解析
2020/09/05 Python
Python Selenium破解滑块验证码最新版(GEETEST95%以上通过率)
2021/01/29 Python
Europcar澳大利亚官网:全球汽车租赁领域的领导者
2019/03/24 全球购物
英国PC组件和在线电脑商店:SCAN
2019/04/18 全球购物
简述synchronized和java.util.concurrent.locks.Lock的异同
2014/12/08 面试题
西安夏日科技有限公司Java笔试题
2013/01/11 面试题
大学自主招生自荐信范文
2014/02/26 职场文书
购房公证委托书(2014版)
2014/09/12 职场文书
领导工作表现评语
2015/01/04 职场文书
任命书怎么写
2015/03/02 职场文书
个人总结格式范文
2015/03/09 职场文书
公司人事任命通知
2015/04/20 职场文书
温馨祝福晨语:美丽的一天从我的问候开始
2019/11/28 职场文书
每日六道java新手入门面试题,通往自由的道路
2021/06/30 Java/Android
JS 基本概念详细介绍
2021/10/16 Javascript
js前端面试常见浏览器缓存强缓存及协商缓存实例
2022/06/21 Javascript