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

其实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]

插入排序

原理:

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

如图所示

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

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

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

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

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

下面是一张gif图

特点:

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

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

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

比冒泡排序快一点

代码实现:

//插入排序
//假定当前元素之前的元素已经排好序,先把自己的位置空出来,
//然后前面比自己大的元素依次向后移,直到空出一个"坑",
//然后把目标元素插入"坑"中
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),即所有记录放在同一组中进行直接插入排序为止。

这里增量的取法如下:

第一次增量的取法为: 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、将两个排序好的子序列合并成一个最终的排序序列。

      

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

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

特点:

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

属于分治思想,递归归并

代码实现:

/* 排序并合并*/
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

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

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

    

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

代码实现:

// 大致分三步:
// 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]

选择排序

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

静态图:

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

代码实现:

// 在无序区中选出最小的元素,然后将它和无序区的第一个元素交换位置。
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]

奇偶排序

原理:

选取所有奇数列的元素与其右侧相邻的元素进行比较,将较小的元素排序在前面;
    选取所有偶数列的元素与其右侧相邻的元素进行比较,将较小的元素排序在前面;
    重复前面两步,直到所有序列有序为止。

 如下图所示:

gif图:

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

代码实现:

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算法的更多相关文章

  1. JavaScript算法题之–随机数的生成

    JavaScript算法题之–随机数的生成 需求描述:从一组有序的数据中生成一组随机并且不重复的数,类似于简单的抽奖程序的实现. 先来生成一个有序的数组: 1 var arr = [], 2      ...

  2. 轻松搞定javascript变量(闭包,预解析机制,变量在内存的分配 )

    变量:  存储数据的容器     1.声明        var   2.作用域       全局变量. 局部变量. 闭包(相对的全局变量):   3.类型         a.基本类型(undefi ...

  3. 来一轮带注释的demo,彻底搞懂javascript中的replace函数

    javascript这门语言一直就像一位带着面纱的美女,总是看不清,摸不透,一直专注服务器端,也从来没有特别重视过,直到最近几年,javascript越来越重要,越来越通用.最近和前端走的比较近,借此 ...

  4. 一张图彻底搞懂JavaScript的==运算

    一张图彻底搞懂JavaScript的==运算 来源 https://zhuanlan.zhihu.com/p/21650547 PS:最后,把图改了一下,仅供娱乐 : ) 大家知道,==是JavaSc ...

  5. 14招搞定JavaScript调试

    14招搞定JavaScript调试 译者按: 很多时候,大家可能只是依靠console.log来调试JavaScript代码,这样做的局限性不言而喻,这篇博客将教你几招实用的调试技巧. 原文: The ...

  6. 《JavaScript算法》常见排序算法思路与代码实现

    冒泡排序 通过相邻元素的比较和交换,使得每一趟循环都能找到未有序数组的最大值或最小值. 最好:O(n),只需要冒泡一次数组就有序了. 最坏: O(n²) 平均: O(n²) *单项冒泡 functio ...

  7. javascript算法汇总(持续更新中)

    1. 线性查找 <!doctype html> <html lang="en"> <head> <meta charset="U ...

  8. JavaScript算法与数据结构知识点记录

    JavaScript算法与数据结构知识点记录 zhanweifu

  9. 转:彻底搞清楚javascript中的require、import和export

    原文地址:彻底搞清楚javascript中的require.import和export   为什么有模块概念 理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. 但是,Ja ...

随机推荐

  1. Android 7.1 App Shortcuts使用

    Android 7.1 App Shortcuts使用 Android 7.1已经发了预览版, 这里是API Overview: API overview. 其中App Shortcuts是新提供的一 ...

  2. 前端开发--ppt展示页面跳转逻辑实现

    1. 工程地址:https://github.com/digitalClass/web_page 网站发布地址: http://115.28.30.25:8029/ 2. 今天遇到一个小问题, 同组的 ...

  3. redis数据结构存储Dict设计细节(redis的设计与实现笔记)

    说到redis的Dict(字典),虽说算法上跟市面上一般的Dict实现没有什么区别,但是redis的Dict有2个特殊的地方那就是它的rehash(重新散列)和它的字典节点单向链表. 以下是dict用 ...

  4. 机器学习实战笔记(Python实现)-03-朴素贝叶斯

    --------------------------------------------------------------------------------------- 本系列文章为<机器 ...

  5. python 发送邮件

    # coding=utf-8 import smtplibfrom time import sleepfrom email.mime.text import MIMETextfrom email.mi ...

  6. SQL Server 修改表结构后无法保存的老问题

    在修改表结构后无法保存,这是每次重装SQL Server后都会遇到的问题,好记性不如烂笔头,在这里记一下吧. 保存修改了的表结构时会提示“不允许保存更改.您所做的更改要求删除并重新创建以下表.您对无法 ...

  7. [Unity3D]巧妙利用父级子级实现Camera场景平面漫游

    本文系作者原创,转载请注明出处 入门级的笔者想了一上午才搞懂那个欧拉角的Camera旋转..=.= 在调试场景的时候,每次都本能的按下W想前进,但是这是不可能的(呵呵) 于是便心血来潮想顺便添加个Ke ...

  8. Node6.9.2 —— Http官网笔记整理

    欢迎指导与讨论 : ) 序章 本文概要:http.Agent代理.http.ClientRequest客户端请求.http.server服务器.http.ServerResponse服务器相应.htt ...

  9. [LeetCode] Rectangle Area 矩形面积

    Find the total area covered by two rectilinear rectangles in a2D plane. Each rectangle is defined by ...

  10. underscore 源码解读之 bind 方法的实现

    自从进入七月以来,我的 underscore 源码解读系列 更新缓慢,再这样下去,今年更完的目标似乎要落空,赶紧写一篇压压惊. 前文 跟大家简单介绍了下 ES5 中的 bind 方法以及使用场景(没读 ...