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 相关文章推荐
JavaScript 组件之旅(四):测试 JavaScript 组件
Oct 28 Javascript
你可能不知道的JavaScript的new Function()方法
Apr 17 Javascript
jQuery使用hide方法隐藏指定元素class样式用法实例
Mar 30 Javascript
在JavaScript中处理时间之getHours()方法的使用
Jun 10 Javascript
JS实现点击复选框将按钮或文本框变为灰色不可用的方法
Aug 11 Javascript
通过Jquery.cookie.js实现展示浏览网页的历史记录超管用
Oct 23 Javascript
基于jQuery倒计时插件实现团购秒杀效果
May 13 Javascript
js 获取元素所有兄弟节点的实现方法
Sep 06 Javascript
bootstrap多种样式进度条展示
Dec 20 Javascript
常用的js方法合集
Mar 10 Javascript
import与export在node.js中的使用详解
Sep 28 Javascript
vue 项目中当访问路由不存在的时候默认访问404页面操作
Aug 31 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判断字符以及字符串的包含方法属性
2008/08/30 PHP
从PHP $_SERVER相关参数判断是否支持Rewrite模块
2013/09/26 PHP
php函数指定默认值方法的小例子
2013/12/04 PHP
PHP排序算法之冒泡排序(Bubble Sort)实现方法详解
2018/04/20 PHP
js+css使DIV始终居于屏幕中间 左下 左上 右上 右下的代码集合
2011/03/10 Javascript
jQuery插件分享之分页插件jqPagination
2014/06/06 Javascript
Jquery数字上下滚动动态切换插件
2015/08/08 Javascript
AngularJS入门教程之ng-class 指令用法
2016/08/01 Javascript
WebSocket+node.js创建即时通信的Web聊天服务器
2016/08/08 Javascript
Javascript单例模式的介绍和实例
2016/10/08 Javascript
JavaScript中如何使用cookie实现记住密码功能及cookie相关函数介绍
2016/11/10 Javascript
详解JavaScript模块化开发
2016/12/04 Javascript
利用forever和pm2部署node.js项目过程
2017/05/10 Javascript
javascript+html5+css3自定义提示窗口
2017/06/21 Javascript
JavaScript正则表达式的贪婪匹配和非贪婪匹配
2017/09/05 Javascript
jQuery获取随机颜色的实例代码
2018/05/21 jQuery
详解Nodejs mongoose
2018/06/10 NodeJs
jquery 遍历hash操作示例【基于ajax交互】
2019/10/12 jQuery
JavaScript实现图片伪异步上传过程解析
2020/04/10 Javascript
JS+CSS实现炫酷光感效果
2020/09/05 Javascript
详解vue 中 scoped 样式作用域的规则
2020/09/14 Javascript
深入解析Python中的descriptor描述器的作用及用法
2016/06/27 Python
python 自动批量打开网页的示例
2019/02/21 Python
Django框架首页和登录页分离操作示例
2019/05/28 Python
django 自定义filter 判断if var in list的例子
2019/08/20 Python
自定义django admin model表单提交的例子
2019/08/23 Python
Python使用百度api做人脸对比的方法
2019/08/28 Python
英国领先的办公用品供应商:Viking
2016/08/01 全球购物
迪奥官网:Dior.com
2018/12/04 全球购物
Famous Footwear加拿大:美国多品牌运动休闲鞋店
2018/12/05 全球购物
法定代表人授权委托书范文
2014/08/02 职场文书
家庭贫困证明书(3篇)
2014/09/15 职场文书
2014年党员自我评议总结
2014/09/23 职场文书
辩护词格式
2015/05/22 职场文书
2016五四青年节活动总结范文
2016/04/06 职场文书
Linux系统下安装PHP7.3版本
2021/06/26 PHP