JavaScript 基础排序的实现(二)
继上一篇O(n^2)的排序算法后,这一篇主要记录O(n*logn)的排序算法
1.快排(快速排序)
这一算法的核心思想为,先随机选一个数作为标兵或者说是标记(这个数一般来说选择该无序数组的中间那个元素;此处笔者选取第一个实现算法,当选取完毕后以此标兵为参照将比这个数大的放到他的右边,比他小的放到左边.这样一趟排序过后就能让这个标记左边的数比他小,右边的数都比他大.下一趟排序则分别选取他的左半边数组和右半边数组重复之前的操作(此操作一般由递归实现)当传入的区间只有一个元素的时候那么开始返回不再继续调用函数自身(即为递归的终止条件)因为只有一个数字是必定有序的
递归实现代码如下:
//快速排序(递归)
function QuickSort(arr,start = 0,end = arr.length-1){
if(start<end){//递归结束条件
let [key,l,r] = [parseInt((start+end)/2),start,end];//key为标记的值,l和r 分别表示左边的下标和右边的下标
while(l<r){//当左右下标相遇即完成一趟排序,停止循环
while(l<r && arr[r] >= key){//从后往前找,如果对应下标的数比标记大则不做操作,下标继续前移
r--;
}//循环完成此时arr[r]
//而arr[l]的的值已经被key保存所以下一步则应该找出一个比key大却在key的左边的数放入arr[r]的位置
while(l<r && arr[l] <= key){
l++;
}
[arr[r],arr[l]] = [arr[l],arr[r]];
//这样一次循环就可以让一个在key左边比key大的数放到key的右边,比key小的放到左边
}
QuickSort(arr,start,l-1);//递归调用 -1 是为了避免区间重复
QuickSort(arr,l+1,end);
}
}
下图为将十万倒序数组变为正序的耗费时间:

下面列出非递归版本的快排:
function QuickSort2(arr,start = 0,end = arr.length-1){
let mid = [start,end];//建立一个数组用于存放需要快排的区间的参数,这样循环调用即可
if(start<end){
while(mid.length){//当参数数组中没有参数则停止循环
let [l,r] = [mid.shift(),mid.shift()];//取出数组中最前面的两个数,并对此区间上的数进行快排
let [low,height] = [l,r];
let key = arr[parseInt((l+r)/2)];//选取标兵
while(l<r){
while(l<r && arr[r] >= key){
r--;
}
arr[l] = arr[r];
while(l<r && arr[l] <= key){
l++;
}
arr[r] = arr[l];
arr[l] = key;
}
//当两个参数不相等,即该区间不止一个数时,则将下一个区间的参数存入参数数组
if(low<l)
mid.push(low,l);
if(l+1<height)
mid.push(l+1,height);
}
}
}
对十万逆序数组排序耗时如下:

由于非递归版本数组方法调用较多,故此花费时间略久于递归版本
2.希尔排序
希尔排序和快排一样都是不稳定排序,快速排序的不稳定是因为,标兵的选取并不能直接选取到刚好是区间中中间大小的数,所以当每个区间的第一个数刚好都是该区间最小的数,那么达到快排的最坏情况(以区间的第一个数为标兵为例). 而希尔排序其核心是插入排序所以当数组刚好为逆序时其效率最低,此时也就是希尔排序的最坏情况但与快排不同的是最坏情况的希尔排序速率并不会下降明显.
希尔排序算法的和心在于,利用了当待排序数组基本有序的时候插入排序效率极高的原理,即选取不同的步长对其进行插排,当步长为一时则与普通的插排没有区别,而效率的提升在于经过前期数次的插排使数组基本有序
其代码如下:
function ShellSort(arr) {
let steep = parseInt(arr.length / 2);//计算步长
let length = arr.length;
let tarr = [];//用于存放按步长分出的数组的临时数组
while (steep) {
//只有步长大于1才分组 否则直接插排
if ( steep > 1) {
for (let i = 0; i < steep; i++) {
//此循环将数组分组
for (let j = i; j < length; j = j + steep) {
tarr.push(arr[j]);
}
InsertionSort(tarr);//将分好组的数组进行插排
for (let j = i; j < length; j = j + steep) {
arr[j] = tarr.shift();
}
//排好序的数组映射回原数组
tarr.length = 0;//清空临时数组
}
}else
InsertionSort(arr);
steep = parseInt(steep / 2);
}
}
普通插排耗时如下:

希尔排序耗时如下:

3.归并排序
与快排和希尔排序不同的是归并排序是稳定排序
其核心思想在于当数组只有一个数时肯定是有序的,所以现将数组拆分为一个一个的数,然后在合并的过程中对齐排序,其弊端在于需要占用一个与原数组等长的临时数组空间来存放变量
递归版代码如下:
//归并排序(递归)
function Merge(arr,start,mid,end,temp) {//此函数用于合并数组
let [l,r] = [start,mid+1];//l标示左边需合并数组的初始下标,r同理标示右边数组的初始下标
while(l<=mid && r <= end){
if(arr[l]<=arr[r])
temp.push(arr[l++]);
else
temp.push(arr[r++]);
}
while(l<=mid){
temp.push(arr[l++]);
}
while(r<=end){
temp.push(arr[r++]);
}
while(start<=end){//将排好的临时数组中的数据复制回原数组
arr[start++] = temp.shift();
}
}
function RecursiveSort(arr,start = 0,end = arr.length-1,temp = []){
if(start < end){
let mid = parseInt((start+end)/2);//将数组分为两半
RecursiveSort(arr,start,mid,temp);
RecursiveSort(arr,mid+1,end,temp);
Merge(arr,start,mid,end,temp);//递归的回调途中进行数组的合并
}
}
递归版耗时:

非递归代码:
function RecursiveSort2(arr,start = 0,end = arr.length-1){
let mid = [start,end];
let pra = [];
while(mid.length){//获取参数列表
let [l,r] = [mid.shift(),mid.shift()];
pra.push(l,r);
let m = parseInt((l+r)/2);
if(m>l)
mid.push(l,m);
if(r>m+1)
mid.push(m+1,r);
}
while(pra.length){
let [r,l] = [pra.pop(),pra.pop()];
let m = parseInt((l+r)/2);
Merge(arr,l,m,r,[]); //此函数见上文
}
}
非递归耗时如下:

总结:
快排在数据量大时的优势较为明显,希尔排序适用于中量数据,而当空间要求不限时归并也不失为一种选择
JavaScript 基础排序的实现(二)的更多相关文章
- JavaScript基础知识总结(二)
JavaScript语法 二.数据类型 程序把这些量.值分为几大类,每一类分别叫什么名称,有什么特点,就叫数据类型. 1.字符串(string) 字符串由零个或多个字符构成,字符包括字母,数字,标点符 ...
- javascript基础学习(十二)
javascript之BOM 学习要点: 屏幕对象 History对象 Location对象 一.屏幕对象 Screen对象是一个由javascript自动创建的对象,该对象的主要作用是描述客户端的显 ...
- JavaScript 基础排序的实现(一)
作为一个有追求的前端,忙里偷闲(闲得发慌)地复习了一下基础的排序算法,以此文留念. 本篇主要记录O(n²)复杂度的基础算法O(nlogn)的算法将在下次有空(闲得发慌)时更新 在记录时发现Es6语法中 ...
- JavaScript基础入门教程(二)
说明 前一篇博客介绍了js以及一些关于js基本类型的简单知识,本篇博客将详细介绍js的基础类型,捎带介绍对象类型,更详细的对象类型的说明将后续再讲. js中类型的说明 js中的类型分为基本类型和对象类 ...
- Javascript基础系列之(二)变量
javascript 中变量通过var关键字(variable)来声明的. var school = "beijingyizhong" 也可以通过var 关键字给变量多个值. va ...
- JavaScript基础笔记(十二)Ajax
Ajax 一.XMLHttpRequest对象 一)XHR用法 var xhr = new XMLHttpRequest(); //open()方法,参数一:发送方法,参数二:请求的URL,参数三:是 ...
- javaScript 基础知识汇总(二)
1.运算符 术语或者叫法:一元运算符.二元运算符.运算元(参数) let x=0; x=5+2; //5和2为运算元,“+” 为二元运算符: x=-x; //"-" 为一元运算符 ...
- javascript基础总结之实例(二)
div的显示和隐藏 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...
- 原生javascript 基础动画函数封装(二)
<!DOCTYPE html> <html> <head> <title></title> <style type="tex ...
随机推荐
- .Net圈子里的一些看法
金三银四招聘季,不一定一定要跳巢,但是出去看看行情还是有必要的,所以就有这篇随笔. 首先,这里说的.Net圈子是只两个方面 第一,技术人才,属于人的圈子 第二,技术本身,技术的圈子,也就是技术所涵盖的 ...
- [精华][推荐]CAS SSO 单点登录框架学习 环境搭建
1.了解单点登录 SSO 主要特点是: SSO 应用之间使用 Web 协议(如 HTTPS) ,并且只有一个登录入口. SSO 的体系中有下面三种角色: 1) User(多个) 2) Web 应用( ...
- 关于签名sign的坑
在有些支付文档或其他文档都会要求签名验证 /** * description:签名 * function name:sign * @param $data * @return string */fun ...
- mysql8 出现1521错误解决方法
ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; #修改加密规则 ALTER USER 'ro ...
- form表单内容JSON格式转化
form表单提交时,对于Content-type为application/json是提交时需要转换成json格式,据说form enctype=‘application/json’这样就可以,然而在我 ...
- XML文件的解析—DOM、SAX
一.DOM 解析 思路:获得Document对象,遍历其中节点获得需要的内容 要点: Document : DocuemntBuilderFactory --newDocumentBuilder - ...
- dede网站安全要做的四件事
1,把安装install的文件夹删除:2,关闭member系统,禁止member文件写入:3,把data文件外移到网站根目录之外:4,把included和plus目录的写入权限关闭. 转载自:http ...
- SAS 操作数据集的观测
SAS 操作数据集的观测 1. SAS表达式 表达式是操作数和操作符的序列,该序列会形成一组可执行并产生 结果值的指令.其中,操作数可以是常量.变量或表达式:操作符是表 示比较.数学计算或逻辑运算的 ...
- 解决sqlserver数据库表空间不自动释放问题
在项目中遇到了sql server数据库经过频繁地删减数据后,查询变慢的问题. 我把数据导到另一个库中,发现查询就很快. 查了下原因,根本原因是删除数据并不释放表空间,日志文件太过巨大的原因. 网上查 ...
- tab选项卡--jq
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...