算法笔记(JavaScript版)——排序

本文内容根据Rebert Sedgewick和Kevin Wayne的《算法(第四版)》整理,原代码为java语言,自己修改为JavaScript版本,仅供参考。

排序算法模版

function sort(arr){//此处添加不同的排序算法实现
}
//比较两个数的大小
function less(a, b){return a < b
}
//交换数组中两个数的位置
function exch(arr, i, j){var temp = arr[i];arr[i] = arr[j];arr[j] = temp;
}
//判断数组是否是有序的
function isSorted(arr){var len = arr.length;for(var i = 1; i < len; i++){if(less(arr[i], arr[j])){return false;}}return true;
}

选择排序

对于长度为N的数组,选择排序需要大约(N^2/2)次比较和N次交换

运行时间和输入无关(仅与输入的长度有关)

数据移动是最少的

function selectionSort(arr){var len = arr.length;for(var i = 0; i < len; i++){var min = i;for(var j = i+1; j < len; j++){if(less(arr[j], arr[min])){min = j;}      }exch(arr, i, min)}
}

插入排序

插入排序所需的时间依赖于输入中元素的初始顺序。

对于随机排列的长度为N且主键不重复的数组,平局情况下插入排序需要~(N^2/4)次比较和~(N^2/4)次交换。最坏情况下需要~(N^2/2)次比较和~(N^2/4)次交换,最好情况下需要(N-1)次比较和0次交换。

插入排序对于部分有序的数组很有效,下面是几种典型的部分有序的数组:

  • 数组中每个元素距离它最终的位置都不远。

  • 一个有序的大数组接一个小数组。

  • 数组中只有几个元素的位置不正确。

function insertionSort(arr){var len = arr.length;for(var i = 1; i < len; i++){for(var j = i; j > 0; j--){if(less(arr[j], arr[j-1])){exch(arr, j, j-1)}}}
}

希尔排序

希尔排序是基于插入排序的快速排序算法。

希尔排序的思想是:使数组中任意间隔为h的元素都是有序的。这样的数组被称为h有序数组。在进行排序时,如果h很大,我们就能将元素移动到很远的地方,为实现更小的h有序创造方便。

使用递增序列1,4,13,40,121,364…的希尔排序所需的比较次数不会超过N的若干倍乘以递增序列的长度。

function shellSort(arr){var len = arr.length,h = 1;while(h < len/3){h = 3*h+1;}while(h >=1){for(var i = h; i < len; i++){for(var j = i; j >= h; j-=h){if(less(arr[j], arr[j-h])){exch(arr, j, j-h)}}}h = (h-1)/3;}
}

归并排序

要将一个数组排序,可以先(递归地)将它分成两半分别排序,然后将结果归并起来。

归并排序最吸引人的性质是它能够保证将任意长度为N的数组排序所需时间和NlogN成正比,主要缺点是它所需的额外空间和N成正比。

//原地归并的抽象方法
function merge(arr, lo, mid, hi){var aux = [],i = lo,j = mid+1;for(var k = lo; k <= hi; k++){aux[k] = arr[k]}for(var m = lo; m <= hi; m++){if(i > mid){arr[m] = aux[j++];}else if(j > hi){arr[m] = aux[i++];}else if(less(aux[j], aux[i])){arr[m] = aux[j++];}else{arr[m] = aux[i++];}}
}
//自顶向下的归并排序
function mergeSort(arr, lo, hi){if(hi <= lo){return;}var mid = Math.floor(lo + (hi - lo)/2);mergeSort(arr, lo, mid);mergeSort(arr, mid+1, hi);merge(arr, lo, mid, hi);
}

对于长度为N的任意数组,自顶向下的归并排序需要(1/2)NlgNNlgN次比较。

对于长度为N的任意数组,自顶向下的归并排序最多需要访问数组6NlgN次。

通过一些细致的思想可以大幅度缩短归并排序的运行时间:

  • 对小规模子数组使用插入排序

  • 测试数组是否已经有序

  • 不将元素复制到辅助数组

//自底向上的归并排序
function mergeSortBU(arr){var len = arr.length;for(var sz = 1; sz < len; sz = sz+sz){for(var lo = 0; lo < len-sz; lo += sz+sz){merge(arr, lo, lo+sz-1, Math.min(lo+sz+sz-1, len-1));}}
}

对于长度为N的任意数组,自底向上的归并排序需要(1/2)NlgNNlgN次比较,最多访问数组6NlgN次。

当数组长度为2的幂时,自顶向下和自底向上的归并排序所用的比较次数和数组访问次数相同,其他时候两种方法的比较和数组访问次序会有所不同。

自底向上的归并排序比较适合用链表组织的数据。

快速排序

快速排序是一种分治的排序算法。

将长度为N的无重复数组排序,快速排序平均需要(~2NlnN)次比较(以及1/6的交换)

快速排序最多需要约(N^2/2)次比较,但随机打乱数组能够预防这种情况。

//快速排序
function quickSort(arr, lo, hi){if(hi <= lo){return;}var j = partition(arr, lo, hi);quickSort(arr, lo, j-1);quickSort(arr, j+1, hi);
}
//快速排序的切分
function partition(arr, lo, hi){var i = lo,j = hi + 1,v = arr[lo];while(true){while(less(arr[++i], v)){if(i === hi){break;}}while(less(v, arr[--j])){if(j === lo){break;}}if(i >= j){break;}exch(arr, i, j);}exch(arr, lo, j);return j;
}

快速排序改进方法:

  • 切换到插入排序

    //快速排序
    function quickSort(arr, lo, hi){//if(hi <= lo){//  return;//}if(hi <= lo + M){//转换参数M的最佳值与系统相关//大多数情况下5~15之间的任意值都能令人满意insertionSort(arr, lo, hi);return;}var j = partition(arr, lo, hi);quickSort(arr, lo, j-1);quickSort(arr, j+1, hi);
    }
  • 三取样切分,使用子数组的一小部分元素的中位数来切分数组

  • 熵最优的排序

对于存在大量重复元素的数组,三向切分的快速排序比标准的快速排序的效率高得多。

对于大小为N的数组,三向切分的快速排序需要~(2ln2)NH次比较,其中H为由主键值出现频率定义的香农信息量。

//三向切分的快速排序
function quick3WaySort(arr, lo, hi){if(hi <= lo){return;}var lt = lo,i = lo + 1,gt = hi;var v = arr[lo];while(i <= gt){if(less(arr[i], v)){//arr[i]小于v时,交换arr[lt]和arr[i],将lt和i加1exch(arr, lt++, i++);}else if(less(v, arr[i])){//arr[i]大于v时,交换arr[i]和arr[gt],将gt减1exch(arr, i, gt--);}else{//arr[i]等于v时,将i加1i++;}}quick3WaySort(arr, lo, lt-1);quick3WaySort(arr, gt+1, hi);
}

算法笔记(JavaScript版)——排序相关推荐

  1. 插入排序---希尔插入排序算法(Javascript版)

    取一个小于n的整数作为第一个增量,把序列分组.所有距离为增量的倍数的元素放在同一个组中.先在各组内进行直接插入排序:然后,取第二个增量(第二个<第一个)重复上述的分组和排序,直至所取的增量=1, ...

  2. 算法笔记_036:预排序(Java)

    目录 1 问题描述 2 解决方案 2.1 检验数组中元素的唯一性 2.2 模式计算   1 问题描述 在计算机科学中,预排序是一种很古老的思想.实际上,对于排序算法的兴趣很大程度上是因为这样一个事实: ...

  3. 《算法笔记》-各种排序算法、散列、递归、贪心、二分、双指针、随机选择算法(知识点+例题+代码)

    一.排序 1.冒泡排序 进行数组大小-1趟排序 int a[]={3,4,1,5,2};//从小到大排序 //第一趟 3,4,

  4. 算法笔记4.1--EXCEL排序

    题目描述 Excel可以对一组纪录按任意指定列排序.现请你编写程序实现类似功能. 对每个测试用例,首先输出1行"Case i:",其中 i 是测试用例的编号(从1开始).随后在 N ...

  5. 算法笔记1926ProblemC Excel排序

    题目描述 Excel可以对一组纪录按任意指定列排序.现请你编写程序实现类似功能. 对每个测试用例,首先输出1行"Case i:",其中 i 是测试用例的编号(从1开始).随后在 N ...

  6. 交换排序---冒泡排序算法(Javascript版)

    比较相邻的元素.如果第一个比第二个大,就交换他们两个. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大的数. 针对所有的元素重复以上的步骤,除了最后一个. ...

  7. JavaScript的排序算法——快速排序

    排序算法(Sorting algorithm)是计算机科学最古老.最基本的课题之一.要想成为合格的程序员,就必须理解和掌握各种排序算法. 快速排序(Quicksort)是对冒泡排序的一种改进. 快速排 ...

  8. JavaScript学习总结(15)——十大经典排序算法的JS版

    前言 这世界上总存在着那么一些看似相似但有完全不同的东西,比如雷锋和雷峰塔,小平和小平头,玛丽和马里奥,Java和javascript-.当年javascript为了抱Java大腿恬不知耻的让自己变成 ...

  9. javascript进制转换_《算法笔记》3.5小节——入门模拟-gt;进制转换

    @[TOC] # Contest100000579 - <算法笔记>3.5小节--入门模拟->进制转换 ## 例题 ### PATB1022 PTA | 程序设计类实验辅助教学平台 ...

最新文章

  1. LiveVideoStackCon讲师热身分享 ( 十五 ) —— 教育场景下的实时音视频解决方案
  2. C语言 文件操作9--fgetc()和fputc()
  3. 跟随光标下划线导航插件
  4. Python+Opencv颜色和形状检测
  5. highcharts 显示网格
  6. 计算机绘图国标规定,(0922202计算机绘图大作业.doc
  7. java第七章jdbc课后简答题_jsp编程基础第七章习题
  8. 链接报错:ld: 1 duplicate symbol for architecture x86_64
  9. QGIS安装与使用教程
  10. 从Log4j迁移到LogBack的理由
  11. 淘宝为什么放弃SpringCloud、Dubbo,选择了这个牛逼的神仙框架!贼爽
  12. 1.1 UWP应用简介
  13. Mysql获取当天用户生日
  14. Python win8安装
  15. Timeboxing——业界大佬都在用的时间管理法
  16. android 辅助功能(无障碍) AccessibilityService 实战入门详解
  17. python爬虫_网易音乐歌单
  18. 闲聊人工智能产品经理(AIPM)—人工智能产品需求
  19. 用计算机模拟沉船,古希腊沉船的宝物 安提凯希拉被称为古老的计算器
  20. MATLAB-数据类型之复数、字符串

热门文章

  1. centos下搭建网站服务器,Centos7搭建web服务器
  2. 实现option上下移动_Perona-Malik方程(各向同性非线性扩散实现图像滤波)
  3. jquery 字符串查找_Python Appium 库IOS特有元素查找API介绍
  4. html怎么添加图片幻灯,使用CSS3实现的超酷幻灯图片效果
  5. linux命令怎么查看dat格式的文件,Linux 查看 elf可执行文件格式的两个命令
  6. (2) freemarker入门案例2
  7. C/C++函数调用的压栈模型
  8. 【机器学习】层次聚类
  9. tensorflow综合示例4:逻辑回归:使用Estimator
  10. 2PC到3PC到Paxos到Raft到ISR