博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法学习(一):实现六种快速排序
阅读量:5768 次
发布时间:2019-06-18

本文共 5237 字,大约阅读时间需要 17 分钟。

最近学习算法,先来总结一下复杂度为O(nlog(n))的快速排序,用js封装了一个quickSort对象,提供六种快速排序方法:

(1)单路快排:递归版,非递归版;

(2)双路快排:递归版,非递归版;

(3)三路快排:递归版,非递归版。

概念简介:

1. 单路快排从一个方向开始遍历,将标量值置于正确的位置,即右边的所有值都比标量值大,左边的所有值都比标量值小,等值可置于任意一端。

2. 双路快排是我最早接触的快速排序算法,之前也实现了一版,但是由于当时理解的不是很到位,存在多次不必要的数据交换。并没有完全展现双路快排的思想:从两个方向同时遍历,一次交换会将两个数置于正确的端。

3. 三路快排对于含有大量等值的数据列能够在每趟排序过程中将所有等于标量值的数据置于正确的位置,进而明显缩小排序区间,提高排序效率。

算法实现:

(1)单路快排递归版

var qsort1 = function(arr,lt,gt){    if(lt >= gt){        return;    }    var v = arr[lt], orilt = lt, origt = gt;    lt++;    gt++;    while(lt < gt){        if(arr[lt] <= v){            lt++;        }else{            this.swap(arr,lt,gt-1);            gt--;        }    }    this.swap(arr,orilt,lt-1);    lt--;    qsort1(arr,orilt,lt-1);    qsort1(arr,gt,origt);};

(2)单路快排非递归版

var qsort1nr = function(arr){    if(arr.length <= 0){        return;    }    var tmplt = [];    var tmpgt = [];    tmplt.push(0);    tmpgt.push(arr.length -1);    while(tmplt.length > 0){        var lt = tmplt.shift();        var gt = tmpgt.shift();        if(lt >= gt){            return;        }                var v = arr[lt], orilt = lt, origt = gt;        lt++;        gt++;        while(lt < gt){            if(arr[lt] <= v){                lt++;            }else{                this.swap(arr,lt,gt-1);                gt--;            }        }        this.swap(arr,orilt,lt-1);        lt--;                if(orilt < lt-1){            tmplt.push(orilt);            tmpgt.push(lt-1);        }        if(origt > gt){            tmplt.push(gt);            tmpgt.push(origt);        }    }}

(3)双路快排递归版

var qsort2 = function(arr,lt,gt){    if(lt < gt){        var k = _qsort2(arr,lt,gt);        qsort2(arr,lt,k);        qsort2(arr,k+1,gt);    }};var _qsort2 = function(arr,lt,gt){    var v = arr[lt];    var k = lt;    while(lt < gt){        while(arr[lt+1] <= v && lt < gt){            lt++;        }        while(arr[gt] > v && gt > lt+1){            gt--;        }        if(lt+1 < gt){            this.swap(arr,lt+1,gt);            lt++;            gt--;        }else{            break;        }    }    this.swap(arr,k,lt);    return lt;}

(4)双路快排非递归版

var qsort2nr = function(arr){    if(arr.length <= 0){        return;    }    var tmplt = [],tmpgt = [];    tmplt.push(0);    tmpgt.push(arr.length -1);        while(tmplt.length > 0){        var lt,gt;        lt = tmplt.shift();        gt = tmpgt.shift()        console.log(lt+'=>'+gt);        if(lt >= gt){            continue;        }        var v = arr[lt];        var k = lt,orilt=lt,origt=gt;        while(lt < gt){            while(arr[lt+1] <= v && lt < gt){                lt++;            }            while(arr[gt] > v && gt > lt+1){                gt--;            }            if(lt+1 < gt){                this.swap(arr,lt+1,gt);                lt++;                gt--;            }else{                break;            }        }        this.swap(arr,k,lt);        if(orilt < lt-1){            console.log(orilt+'=>'+(lt-1));            tmplt.push(orilt);            tmpgt.push(lt-1);        }        if(gt < origt){            console.log(gt+'=>'+origt);            tmplt.push(gt);            tmpgt.push(origt);        }    }}

(5)三路快排递归版

var qsort3 = function(arr,lt,gt){    if(lt >= gt){        return;    }    var orilt = lt, origt = gt, e = lt;    var v = arr[e];    e++;    gt++;    while(e < gt){        if(arr[e] == v){            e++;        }else if(arr[e] < v){            if(e != lt+1){                this.swap(arr,e,lt+1);            }            lt++;            e++;        }else if(arr[e] > v){            this.swap(arr,gt-1,e);            gt--;        }    }    this.swap(arr,orilt,lt);    lt--;        qsort3(arr,orilt,lt);    qsort3(arr,gt,origt);}

(6)三路快排非递归版

var qsort3nr = function(arr){    if(arr.length <= 0){        return;    }    var tmplt = [];    var tmpgt = [];    tmplt.push(0);    tmpgt.push(arr.length-1);    while(tmplt.length > 0){        var lt = tmplt.shift();        var gt = tmpgt.shift();        if(lt >= gt){            return;        }        var orilt = lt, origt = gt, e = lt;        var v = arr[e];        e++;        gt++;        while(e < gt){            if(arr[e] == v){                e++;            }else if(arr[e] < v){                if(e != lt+1){                    this.swap(arr,e,lt+1);                }                lt++;                e++;            }else if(arr[e] > v){                this.swap(arr,gt-1,e);                gt--;            }        }        this.swap(arr,orilt,lt);        lt--;        if(orilt < lt){            tmplt.push(orilt);            tmpgt.push(lt);        }        if(gt < origt){            tmplt.push(gt);            tmpgt.push(origt);        }    }}

交换数组两个位置的数值(int型):

//交换两个整数值var swap = function(arr,x,y){    if(arr[x] == arr[y]){        return;    }    arr[x] = (arr[x]) ^ (arr[y]);    arr[y] = (arr[x]) ^ (arr[y]);    arr[x] = (arr[x]) ^ (arr[y]);};

总结:

(1)递归到非递归的转换主要是记录每次排序的区间起始位置。在递归版算法中编译器替我们记录了每次递归调用应该返回的位置,所以在非递归版算法中我们要自己承担这一份责任;

(2)在非递归版算法中记录每次递归区间需要用到栈这一数据结构,可以用js的数组模拟栈的功能,这里我用了两个栈分别存储排序区间的起始位置与结束位置,其实完全可以用一个栈来做这件事情,但是要注意入栈和出栈的顺序。

(3)实现上述算法的过程中最容易出现问题的是区间指针的开闭状态,当前lt是指向比标量值小的所有数值的最后一个,还是指向下一个,其实这里开闭状态可以随意设定,但是交换数据以及越界判断等地方一定要与设定的区间状态相协调。

转载于:https://www.cnblogs.com/ling-diary/p/9294117.html

你可能感兴趣的文章
re:Invent大会第四天:为什么Lambda值得你更多关注?
查看>>
前端tree优化实践:渲染速度从14.65s到0.49s
查看>>
如何通过StackStorm自动支持2万多台服务器
查看>>
深入探索JVM自动资源管理
查看>>
符合架构的测试
查看>>
又拍云创新CDN服务,同步提供1:1免费云存储
查看>>
微软必应从.NET Core 2.1获得了性能提升
查看>>
2019年DApp调查报告
查看>>
职场新人不太适合参加的活动
查看>>
Web开发新变化:Chrome启用安全自动增强策略
查看>>
AI一周热闻:GitHub免费开放无限私有库;苹果市值蒸发超450亿美元;小米入股TCL...
查看>>
Android简易“吹一吹实现”以及录音和播放示例
查看>>
从战争到外包软件开发:如何赢得最后胜利
查看>>
PostgreSQL中的大容量空间探索时间序列数据存储
查看>>
Node.js和io.js将合并到Node基金会下
查看>>
腾讯云自主可控数据库TDSQL的架构演进\n
查看>>
架构师的狂欢—ArchSummit深圳2016等您来约
查看>>
Netflix:当你按下“播放”的时候发生了什么?
查看>>
唯品会HDFS性能挑战和优化实践
查看>>
道德规范的心理学透视
查看>>