资讯专栏INFORMATION COLUMN

温故js系列(2)-快速排序&插入排序&选择排序&冒泡排序算法&优化

ningwang / 1681人阅读

摘要:优化当待排序序列长度时,使用插入排序,可以加速排序。插入排序原理通过构建有序序列,对于未排序元素,在已排序序列中从后向前扫描,找到相应位置并插入。堆排序可通过树形结构保存部分比较结果,可减少比较次数。

前端学习:教程&开发模块化/规范化/工程化/优化&工具/调试&值得关注的博客/Git&面试-前端资源汇总

欢迎提issues斧正:排序算法

JavaScript-排序算法及简易优化 快速排序

原理:在待排序序列中选一个分割元素,将待排序序列分隔成独立的子序列,子序列1里的元素比分割元素元素都小(大),子序列2反之,递归进行此操作,以达到子序列都有序。最后将子序列用concat方法连接起来即是排序好的序列。

function quickSort(arr){
    if(arr.length <= 1){
        return arr;
    }    
    var num = Math.floor(arr.length/2);
    var numValue = arr.splice(num,1);

    var left = [];
    var right = [];
    for(var i = 0;i

优化:当待排序序列长度N < 10时,使用插入排序,可以加速排序。

function quickSort(arr){
    if(arr.length <= 1){
        return arr;
    }
    if(arr.length < 10){
        insertSort(arr);
    }    
    var num = Math.floor(arr.length/2);
    var numValue = arr.splice(num,1);

    var left = [];
    var right = [];
    for(var i = 0;i
插入排序

原理:通过构建有序序列,对于未排序元素,在已排序序列中从后向前扫描,找到相应位置并插入。一般可以将第一个元素作为有序序列,用未排序的元素与之相比,插入,直到排序完毕。

function insertSort(arr){
    var len = arr.length;
    if(len <= 1){
        return arr;
    }
    for(var i = 1;i tmp){
            arr[j] = arr[j-1];
            --j;
        }
        arr[j] = tmp;
    }
    return arr;
}
console.log(insertSort([1,45,43,4,56,7,20,1]));
//[1, 1, 4, 7, 20, 43, 45, 56]

优化:二分插入排序,在有序序列中使用二分查找法查找一个插入位置,减少元素比较次数

function binaryInsertSort(arr){
    var len = arr.length;
    if(len <= 1){
        return arr;
    }
    for (var i = 1; i < len; i++) {
        var tmp = arr[i], left = 0, right = i - 1;
        while (left <= right) {
              var index = parseInt((left + right) / 2);
              if (tmp < arr[index]) {
                  right = index - 1;
              } else {
                left = index + 1;
              }
        }
        for (var j = i - 1; j >= left; j--) {
              arr[j + 1] = arr[j];
        }
        arr[left] = tmp;
      }
    return arr;
}
console.log(binaryInsertSort([1,45,43,4,56,7,20,1,2,3,4,56,3]));
//[1, 1, 2, 3, 3, 4, 4, 7, 20, 43, 45, 56, 56]
选择排序

原理:在待排序序列中找到最小(大)元素,放在序列的起始位置,然后,再从剩余元素中寻找最小(大)元素,然后放到已排序序列的末尾。重复,直到所有元素均排序完毕。

Array.prototype.selectionSort = Array.prototype.selectionSort || function(){
    var len = this.length;
    if(len <= 1){
        return this;
    }    
    var min,tmp;
    for(var i = 0;i

优化:堆排序,在直接选择排序中,为了从序列中选出关键字最小(最大)的记录,必须进行n-1次比较,接着在剩下序列中选出最小(最大)的元素,又需要做n-2次比较。但是,在n-2次比较中,有的比较可能在前面的n-1次比较中已经做过,但由于前一趟排序时未保留这些比较结果,所以后一趟排序时又重复执行了这些比较操作。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可通过树形结构保存部分比较结果,可减少比较次数。

function heapSort(arr) { 
     function swap(arr, i, j) {
          var temp = arr[i];
          arr[i] = arr[j];
          arr[j] = temp;
    }
 
     function maxHeapify(arr, index, heapSize) {
          var iMax,iLeft,iRight;
          while (true) {
               iMax = index;
               iLeft = 2 * index + 1;
               iRight = 2 * (index + 1);
 
               if (iLeft < heapSize && arr[index] < arr[iLeft]) {
                iMax = iLeft;
               }
 
               if (iRight < heapSize && arr[iMax] < arr[iRight]) {
                iMax = iRight;
               }
 
               if (iMax != index) {    
                swap(arr, iMax, index);
                index = iMax;
               } else {
                    break;
               }
          }
     }
 
     function buildMaxHeap(arr) {
          var i,iParent = Math.floor(arr.length / 2) - 1;
 
          for (i = iParent; i >= 0; i--) {
               maxHeapify(arr, i, arr.length);
          }
     }
 
     function sort(arr) {
          buildMaxHeap(arr);
 
          for (var i = arr.length - 1; i > 0; i--) {
               swap(arr, 0, i);
               maxHeapify(arr, 0, i);
          }
          return arr;
     }
 
     return sort(arr);
}
console.log(heapSort([1,45,43,4,56,7,20,1,2,3,4,56,3]));
//[1, 1, 2, 3, 3, 4, 4, 7, 20, 43, 45, 56, 56]
冒泡排序

原理:从第一个元素开始,一次比较两个元素,如果arr[n]大于arr[n+1],就交换。重复遍历直到没有再需要交换,排序完成。

function bubbleSort(arr){
    var len = arr.length;
    if(len <= 1){
        return arr;
    }
    var tmp;
    for(var i = 0;i

优化:上面代码中,里面一层循环在某次扫描中没有发生交换,说明此时数组已经全部排好序,后面的步骤就无需再执行了。因此,增加一个标记,每次发生交换,就标记,如果某次循环完没有标记,则说明已经完成排序。

function bubbleSort(arr)  {  
    var len = arr.length;
    if(len <= 1){
        return arr;
    }
    var bSwaped = true;  
    for (var i = 0; i < len -1; i++)  {  
        // 每次先重置为false  
        bSwaped = false;  
        for (var j = len - 1; j > i ; j--)  {  
            if (arr[j-1] > arr[j])  {  
                var temp = arr[j-1];  
                arr[j-1] = arr[j];  
                arr[j] = temp;  
  
                bSwaped = true;  
            }  
        }  
        // 如果上一次扫描没有发生交换,则说明数组已经全部有序,退出循环  
        if (!bSwaped){
            break;
        }              
    }  
    return arr;
}  
console.log(bubbleSort([1,45,43,4,56,7,20,1]));
//[1, 1, 4, 7, 20, 43, 45, 56]

在上一步优化的基础上进一步思考:如果R[0..i]已是有序区间,上次的扫描区间是R[i..n],记上次扫描时最后一次发生交换的位置是lastSwapPos,那么lastSwapPos会在在i与n之间,所以R[i..lastSwapPos]区间是有序的,否则这个区间也会发生交换;所以下次扫描区间就可以由R[i..n]缩减到[lastSwapPos..n] :

function bubbleSort(arr){ 
    var len = arr.length;
    if(len <= 1){
        return arr;
    } 
    var lastSwapPos = 0, lastSwapPosTemp = 0;  
    for (var i = 0; i < len - 1; i++){  
        lastSwapPos = lastSwapPosTemp;  
        for (var j = len - 1; j > lastSwapPos; j--){  
            if (arr[j - 1] > arr[j]){  
                var temp = arr[j - 1];  
                arr[j - 1] = arr[j];  
                arr[j] = temp;  
  
                lastSwapPosTemp = j;  
            }  
        }  
        if (lastSwapPos == lastSwapPosTemp){
            break;
        }                         
    }  
    return arr;
}
console.log(bubbleSort([1,45,43,4,56,7,20,1]));
//[1, 1, 4, 7, 20, 43, 45, 56]

这一些列优化都需要测速才知道有没有优化成功,只是简单的测试一两个数组是不容易看出来的。我们可以造一些很大的数据去测试,再用一个比较简单的测试时间的方法,随机创建10万个数:

var arr = [];
var num = 0;
for(var i = 0; i < 100000; i++){
    num = Math.floor(Math.random()*100000);
    arr.push(num);
}
console.time("testTime");
bubbleSort(arr);
console.timeEnd("testTime");
==> testTime: 21900.684ms (比较数目越多,差距越大,更好对比)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79911.html

相关文章

  • DS&amp;ALGR : 通过简单排序理解大O表示法

    摘要:在上面的三种排序中,它们的效率为用大表示法来表示都是,但实际上按比较的次数和交换的次数来考虑,插入排序效率高于选择排序,选择排序效率高于冒泡排序。大表示法常见的基于的走势图如下图所示 大O表示法初体验 身在斯洛文尼亚的阿拉里克得到斯提里科被杀的消息后,仰天大笑:终于没有人能阻止我去罗马了。当他手下的将军问:不知大王打算走哪条路去罗马?西哥特王哈哈大笑,说出了那句千古名言:All roa...

    Eirunye 评论0 收藏0
  • 温故js系列(16)-数组&amp;数组方法使用详解

    摘要:创建数组数组字面量数组构造函数参数为数组建议使用数组字面量方式,性能好,代码少,简洁,毕竟代码少。数组判断方法用来判断某个值是否为。的这是最简洁最直接的遍历数组元素的语法。把数组转换为本地数组,并返回结果。 前端学习:前端教程&开发模块化/规范化/工程化/优化&工具/调试&值得关注的博客/Git&面试-前端资源汇总 欢迎提issues斧正:数组&数组方法使用详解 Array对象 之前一...

    morgan 评论0 收藏0
  • Deep in JS - 收藏集 - 掘金

    摘要:今天同学去面试,做了两道面试题全部做错了,发过来给道典型的面试题前端掘金在界中,开发人员的需求量一直居高不下。 排序算法 -- JavaScript 标准参考教程(alpha) - 前端 - 掘金来自《JavaScript 标准参考教程(alpha)》,by 阮一峰 目录 冒泡排序 简介 算法实现 选择排序 简介 算法实现 ... 图例详解那道 setTimeout 与循环闭包的经典面...

    enali 评论0 收藏0
  • 前端资源系列(4)-前端学习资源分享&amp;前端面试资源汇总

    摘要:特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 特意对前端学习资源做一个汇总,方便自己学习查阅参考,和好友们共同进步。 本以为自己收藏的站点多,可以很快搞定,没想到一入汇总深似海。还有很多不足&遗漏的地方,欢迎补充。有错误的地方,还请斧正... 托管: welcome to git,欢迎交流,感谢star 有好友反应和斧正,会及时更新,平时业务工作时也会不定期更...

    princekin 评论0 收藏0
  • Java编程基础14——常见对象_StringBuffer&amp;数组排序&amp;包装类

    摘要:提供了排序,查找等功能。常用操作常用的操作之一用于基本数据类型与字符串之间的转换。 1_StringBuffer类的概述 A:StringBuffer类概述 通过JDK提供的API,查看StringBuffer类的说明 线程安全的可变字符序列 (一个类似于 String 的字符串缓冲区,但不能修改 : 不能像String那样用 + 连接来修改String) B:String...

    banana_pi 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<