栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

对数据结构和算法的总结和思考(四)--快速排序

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

对数据结构和算法的总结和思考(四)--快速排序

快速排序,顾名思义就是快,多快呢?亲测了下,整体性能除了计数排序无人能比,不过计数排序有一个很大的劣势是只能对整数进行排序,这就大大限制了使用场景。所以,快速排序应该是目前表现最好的排序方法,各种解释器都有快速排序的实现,并且快速排序实现简单易于理解。实现原理:找出一个标杆元素,将比标杆元素大的放到右边,小的放到左边,然后递归合并。具体代码如下:

// 快速排序

// 找出基准值,取出基准值,遍历放入

function quick(arr) {
    if (arr.length < 2) return arr;

    let flag = parseInt(arr.length / 2);
    let flagValue = arr.splice(flag, 1);

    let leftArr = [], rightArr = [];
    for (let i = 0; i < arr.length; i ++) {
 if (arr[i] > flagValue[0]) {
     rightArr.push(arr[i]);
 } else {
     leftArr.push(arr[i]);
 }
    }

    return quick(leftArr).concat(flagValue).concat(rightArr);
}

let sortArr = [];
for (let i = 0;i < 1000; i ++) {
    sortArr.push(parseInt(Math.random() * 10000));
}

console.time('native sort ');
console.log(sortArr.sort(function(a, b) {
    return a- b;
}));
console.timeEnd('native sort ');

console.time('快速排序耗时 ');
console.log(quick(sortArr));
console.timeEnd('快速排序耗时 ');

这里用了js内置排序算法和快速排序比较,表现性能差不多。快速排序有个地方需要注意,一定要吧标杆元素取出来,然后再循环数组,不然很肯能出现死循环的情况。

既然快速排序是根据标杆元素来分开元素,那么标杆元素的选取就会严重的影响性能,如果不小心选到了最小的一个,那么恭喜你,你取到了快速排序最慢的情况,时间复杂度为O(n^2)和基本排序速度一样了。如果想要优化快速排序,那最好的优化方式就是优化中间元素的选取。

还好,先贤已经找到了相对较好的选取中值的方法,一种是元素个数不多的时候采用三分法,具体实现是选取一组共三个元素,取出三个元素的中的中值,这个值就有更大的几率接近于中值,起码不是最大或者最小值。一种是元素个数多的时候取三组每组三个共九个元素的九分法,具体实现是分别取出三组中的中值,然后再从三组中值中取出中值。

下面我们采用三分法对快速排序进行优化,引入一个区中值的文件getMiddle.js

let swap = require('./swap.js');
function getMiddle(arr, low, m, high) {
    let middleIndex = m;
    if (arr[low] > arr[high]) {
 swap(arr, low, high);
    }
    if (arr[high] < arr[m]) {
 swap(arr, high, m);
 middleIndex = high;
    }
    if (arr[low] > arr[m]) {
 swap(arr, low, m);
 middleIndex = low;
    }
    return middleIndex;
}

module.exports = getMiddle;

然后快速排序代码稍微改造下:

let count = 0;
let getMiddle = require('./getMiddle.js');
function quick(arr) {
   if (arr.length < 2) return arr;
   let middle = getMiddle(arr, 0, parseInt(arr.length / 2), arr.length - 1),
//    let middle = parseInt(arr.length / 2),
  left = [], 
  right = [];
   let middlevalue = arr.splice(middle, 1);
   for (let i = 0; i < arr.length; i ++) {
count ++;
arr[i] > middlevalue[0] ? right.push(arr[i]) : left.push(arr[i]);
   }
   return quick(left).concat(middlevalue).concat(quick(right));
}

let arr = [2, 4,5, 1, 3, 6, 9, 4]

console.log(quick(arr));
console.log(count);

这样就对中值选取进行了改进,使快速排序进行了优化。还有一种思路是从快速排序的递归入手,递归会不停地吃内存,那么优化递归也就能优化在大数据量情况下的快速排序。怎么优化呢,尾递归。

下面是一个尾递归转化函数:

function tco(f) {
    let funcStack = [],
 active = false,
 value;
    return function() {
 funcStack.push(arguments);
 if (active) return;
 active = true;
 while (funcStack.length) {
     value = f.apply(this, funcStack.shift());
 }
 active = false;
 return value;
    }
}

上面代码中,tco函数是尾递归优化的实现,它的奥妙就在于状态变量active。默认情况下,这个变量是不激活的。一旦进入尾递归优化的过程,这个变量就激活了。然后,每一轮递归sum返回的都是undefined,所以就避免了递归执行;而accumulated数组存放每一轮sum执行的参数,总是有值的,这就保证了accumulator函数内部的while循环总是会执行。这样就很巧妙地将“递归”改成了“循环”,而后一轮的参数会取代前一轮的参数,保证了调用栈只有一层。

所以优化后的实现为:

var count = 0;
var getMiddle = require('./getMiddle.js');

function tco(f) {
    let funcStack = [],
 active = false,
 value;
    return function() {
 funcStack.push(arguments);
 if (active) return;
 active = true;
 while (funcStack.length) {
     value = f.apply(this, funcStack.shift());
 }
 active = false;
 return value;
    }
}

function quick(arr) {
   if (arr.length < 2) return arr;
   let middle = getMiddle(arr, 0, parseInt(arr.length / 2), arr.length - 1),
//    let middle = parseInt(arr.length / 2),
  left = [], 
  right = [];
   let middlevalue = arr.splice(middle, 1);
   for (let i = 0; i < arr.length; i ++) {
count ++;
arr[i] > middlevalue[0] ? right.push(arr[i]) : left.push(arr[i]);
   }
   return quick(left).concat(middlevalue).concat(quick(right));
}

var arr = [2, 4,5, 1, 3, 6, 9, 4]
var quick2 = tco(quick);
console.log(quick2(arr));
// console.log(count)

当然关于尾递归优化大家可以参看阮一峰的es6标准入门,地址为:
http://es6.ruanyifeng.com/#docs/function#
以上就是整个快速排序的内容,下一篇将分享堆排序,thx。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/225725.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号