v8 sort方法部分关于快速排序法的源码:

function QuickSort(a, from, to) {
// Insertion sort is faster for short arrays.
if (to - from <= 22) {
InsertionSort(a, from, to);
return;
}
var pivot_index = $floor($random() * (to - from)) + from;
var pivot = a[pivot_index];
// Pre-convert the element to a string for comparison if we know
// it will happen on each compare anyway.
var pivot_key =
(custom_compare || %_IsSmi(pivot)) ? pivot : ToString(pivot);
// Issue 95: Keep the pivot element out of the comparisons to avoid
// infinite recursion if comparefn(pivot, pivot) != 0.
a[pivot_index] = a[from];
a[from] = pivot;
var low_end = from; // Upper bound of the elements lower than pivot.
var high_start = to; // Lower bound of the elements greater than pivot.
// From low_end to i are elements equal to pivot.
// From i to high_start are elements that haven't been compared yet.
for (var i = from + 1; i < high_start; ) {
var element = a[i];
var order = Compare(element, pivot_key);
if (order < 0) {
a[i] = a[low_end];
a[low_end] = element;
i++;
low_end++;
} else if (order > 0) {
high_start--;
a[i] = a[high_start];
a[high_start] = element;
} else { // order == 0
i++;
}
}
QuickSort(a, from, low_end);
QuickSort(a, high_start, to);
}

快速排序(Quicksort)是对冒泡排序的一种改进

基本思想:

通过一趟循环将要排序的数据分割成独立的两部分。

其中一部分的所有数据都比另外一部分的所有数据都要小。

然后再按此方法对这两部分数据分别进行快速排序。

整个排序过程可以递归进行,以此达到整个数据变成有序序列。

操作流程:

1、首先设定一个分界值,通过该分界值将数组分成左右两部分。 
2、将大于或等于分界值的数据集中到数组右边或左边,小于分界值的数据集中到数组的左边或右边。
总之要做到以分界值为界,一边的值全部要小于或大于另一边。
继续对两边的数组采用上述1、2操作。
 

跟着快速排序的基本思路和操作流程,对源码进行梳理和理解:

该函数传入参数是数组,起始索引,截至索引。
然后函数的退出条件:源码出于性能的考虑,当索引差值小于23时,使用插入排序方法操作数组,然后return。
这里暂不理会插入排序,把退出条件改为索引差值小于2。即索引对应的值只有一个时,此时无需比较,直接return。

接着是取分界值,在传入的起始索引和截至索引的差值中任取一个索引,该索引对应的值即为分界值,保存副本

需要注意的是,key不应该在循环时被循环出来和自身比较

这里交换数组起始位置值和key_index值。

创建两个变量记录已交换位置的索引。

一个初值等于截至索引,每交换一个值到右边,则该变量减-1。最后该变量和截至索引即为递归函数的from和to。

另一个初值等于开始索引,每交换一个值到左边,则该变量加1。最后开始索引和该变量即为递归函数的from和to。

然后从起始索引加+1开始循环,这很好理解,第一个值是key,本身不需要分,而且只有一个值时没有左边右边的概念。

根据比较结果的不同,分别对大于0,小于0的数组值进行分边。

比较结果大于0,放右边。右边的逻辑:(升降序是通过比较函数来控制)

比较结果小于0,放左边。左边的逻辑:

值相同时,保持原位即可。操作下一个值,令i++。

循环结束后,数组已被边界值分成了两部分,每部分的起始、截至索引都已经记录。

接着把这两部分按照上述逻辑进行操作。循环往复。

以上都是在原数组中操作,并未引入新数组。

例子:

      * 数组[40, 2, 7, 11, 20, 15]。key_index = 3; key = 11。与数组起始值交换后。
      * 此时数组[11, 2, 7, 40, 20, 15]。循环开始,操作a[1],计算结果小于0。分左边。
      * 即a[1] = a[0] = 11; a[0] = el = 2; low_end = 1; i = 2。数组:[2, 11, 7, 40, 20, 15],接着操作a[2]。计算结果小于0。分左边。
      * 即a[2] = a[1] = 11; a[1] = el = 7; low_end = 2; i = 3。数组:[2, 7, 11, 40, 20, 15],接着操作a[3]。计算结果大于0。分右边。
      * 即a[3] = a[5] = 15; a[5] = el = 40; high_start = 5; i = 3。数组:[2, 7, 11, 15, 20, 40],继续操作a[3]。计算结果大于0。分右边。
      * 即a[3] = a[4] = 20; a[4] = el = 15; high_start = 4; i = 3。数组:[2, 7, 11, 20, 15, 40],继续操作a[3]。计算结果大于0。分右边。
      * 即a[3] = a[3] = 20; a[3] = el = 20; high_start = 3; i = 3。数组:[2, 7, 11, 20, 15, 40],i < high_start判断失败,退出循环。
      * 此时 low_end = 2; high_start = 3; from = 0; to = 6。传入quickSort(a, from, low_end)、quickSort(a, high_start, to)递归执行。
 

源码在对未传入比较函数的情况下,对key 进行了toString处理,保证行为的一致性。

源码对比较函数进行了封装。在未传入比较函数时,对两个参数进行了toString处理。

代码:

function quickSort(a, from, to) {
// 递归退出条件,当传入的起始索引和截至索引差值小于2时,此时对应的数据只有一个。已经无需比较
if (to - from < 2) return; const key_index = Math.floor(Math.random() * (to - from)) + from; // key的索引,值的范围在起始索引和截至索引中任取
const key = a[key_index]; // key 用于比较 // 需要注意的是,key不应该在循环时被循环出来和自身比较
// 这里交换数组起始位置值和key值。
a[key_index] = a[from];
a[from] = key; let high_start = to; // 数组分边后其中一边的开始索引
let low_end = from; // 数组分边后另一边的截至索引 // 循环从起始位置+1开始,判断条件中high_start,每交换一个值到右边,该值就减1
for (let i = from + 1; i < high_start;) {
let el = a[i]; // 当前副本,需要被分边
let result = el - key; // 比较。可封装成比较函数,实现升降序 if (result > 0) {
/**
* 右边。high_start--;把high_start对应的值赋给a[i]。
* 此时a[i]已经变了,需要重新比较。故不能i++。把el赋给a[high_start]。el完成分边
*/
high_start--;
a[i] = a[high_start];
a[high_start] = el;
} else if (result < 0) {
/**
* 左边。
* 把左边low_end对应的值赋给a[i]。然后el赋给a[low_end],el完成分边。然后low_end++。
* 此时a[i]是key值。无需比较。继续操作下一个值。即i++
* 当循环至边界索引key_index时,该索引对应的是数组起始值。
* 由此数组每个值都可以与key进行比较,然后被分边。
*/
a[i] = a[low_end];
a[low_end] = el;
low_end++;
i++;
} else {
i++;
}
}
// 此时递归,传入起始索引和截至索引,对两部分数据的进行上述操作
quickSort(a, from, low_end) // 左边组数据
quickSort(a, high_start, to) // 右边组数据
}

v8--sort 方法 源码 (2) 快速排序法的更多相关文章

  1. erlang下lists模块sort(排序)方法源码解析(二)

    上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...

  2. erlang下lists模块sort(排序)方法源码解析(一)

    排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...

  3. v8--sort 方法 源码 (1) 插入排序法

    v8--sort方法源码中对于长度较短的数组使用的是插入排序法. 部分源码: function InsertionSort(a, from, to) { for (var i = from + 1; ...

  4. Java split方法源码分析

    Java split方法源码分析 public String[] split(CharSequence input [, int limit]) { int index = 0; // 指针 bool ...

  5. getOrCreateEnvironment()方法源码探究

    该方法目的是创建一个环境对象,并且根据环境类型,自动判断是创建web环境对象,还是标准非web环境对象. 首先该方法源于prepareEnvironment准备环境: 然后进入该方法源码: 可以发现: ...

  6. TreeSet集合的add()方法源码解析(01.Integer自然排序)

    >TreeSet集合使用实例 >TreeSet集合的红黑树 存储与取出(图) >TreeSet的add()方法源码     TreeSet集合使用实例 package cn.itca ...

  7. invalidate和requestLayout方法源码分析

    invalidate方法源码分析 在之前分析View的绘制流程中,最后都有调用一个叫invalidate的方法,这个方法是啥玩意?我们来看一下View类中invalidate系列方法的源码(ViewG ...

  8. Linq分组操作之GroupBy,GroupJoin扩展方法源码分析

    Linq分组操作之GroupBy,GroupJoin扩展方法源码分析 一. GroupBy 解释: 根据指定的键选择器函数对序列中的元素进行分组,并且从每个组及其键中创建结果值. 查询表达式: var ...

  9. Java线程状态、线程start方法源码、多线程、Java线程池、如何停止一个线程

    下面将依次介绍: 1. 线程状态.Java线程状态和线程池状态 2. start方法源码 3. 什么是线程池? 4. 线程池的工作原理和使用线程池的好处 5. ThreadPoolExecutor中的 ...

随机推荐

  1. 深入解读阿里云Redis开发规范

    Key命名设计:可读性.可管理性.简介性 规范建议使用冒号即:进行分割拼接,因为很多Redis客户端是根据冒号分类的.比如有几个Key:apps:app:1.apps:app:2和apps:app:3 ...

  2. windows系统下设置mtu值的方法

    说起 MTU 值,可能许多朋友连听都没听说过.简单来说,我们上网时所进行的操作,都是通过传输一个又一个“数据包”来实现的,而 MTU 值就是用来设定可传输数据包的最大尺寸的.很显然,MTU 值设置得过 ...

  3. Nexus上传python包

    参考 https://blog.csdn.net/m0_37607365/article/details/79998955 1.首先创建pypi仓库 其中,PyPI类的服务,支持三种: proxy,提 ...

  4. kubernetes 1.9 安装部署

    参考地址:https://github.com/gjmzj/kubeasz 引言 提供快速部署高可用k8s集群的工具,基于二进制方式部署和利用ansible-playbook实现自动化,既提供一键安装 ...

  5. LeetCode_448. Find All Numbers Disappeared in an Array

    448. Find All Numbers Disappeared in an Array Easy Given an array of integers where 1 ≤ a[i] ≤ n (n  ...

  6. [Golang] 消费Kafka的日志提交到ElasticSearch

    0x0 需求 消费Kafka的日志并写入ElasticSearch供查询 0x1 依赖库 golang版Kafka客户端 https://github.com/Shopify/sarama golan ...

  7. SQL Server PARTITION FUNCTION(分区)

    分区并不影响Linq,sql查询 在MSSQL中,选中目标表,右键-存储-创建分区 根据提示完成分区,存储成sql 这里展示如何根据Id的数据范围分区 在执行前,可能需要设置日志文件大小为" ...

  8. (转) 解决django项目部署到nginx+uwsgi服务器后 admin页面样式消失的问题

    原贴地址:https://blog.csdn.net/qq_42571805/article/details/80862455 摘要 uwsgi为主要服务器,nginx为反向代理服务器部署完成之后发现 ...

  9. Excel在数据表中悬停鼠标显示数据值

    打开一个实例文档,鼠标移动到数据表中,在柱状图上中悬停鼠标,可以看到没有显示数据的值. 鼠标单击左上角的<文件>按钮. 然后单击<选项>按钮. 在弹出的excel选项对话框中单 ...

  10. PHP多进程编程初步

    转自:https://www.pureweber.com/article/php-multi-process-programming-preview/ 羡慕火影忍者里鸣人的影分身么?没错,PHP程序是 ...