🥳每日一练-快速排序-JS简单版

前言

这篇文章分享一种排序算法--快速排序

快速排序(Quick Sort)是一种常用的排序算法,其平均时间复杂度为 O(nlogn),通常比其他排序算法表现更好。快速排序的主要思想是分治法,通过递归地将数组划分为较小和较大的两个子数组,然后递归地排序两个子数组。

快速排序的基本步骤如下:

  1. 选择一个基准元素(pivot),通常选择第一个或最后一个元素。
  2. 将数组划分为两个子数组,一个子数组中的元素都比基准元素小,另一个子数组中的元素都比基准元素大。
  3. 对这两个子数组递归地应用快速排序算法,直到子数组的大小为1或0,即它们已经有序。

过程不难,下面用代码实现一下

快速排序

javascript 复制代码
const splitArray = (array, left, right) => {
    // 获取基准元素
    const temp = array[left];
    
    // 循环比较元素,将小于基准元素的元素放到左边,大于等于基准元素的元素放到右边
    while (left < right) {
        while (left < right && array[right] >= temp) right--;
        array[left] = array[right]; // 将右边小于基准元素的元素放到左边
        while (left < right && array[left] < temp) left++;
        array[right] = array[left]; // 将左边大于基准元素的元素放到右边
    }
    
    // 将基准元素放到正确的位置
    array[left] = temp;
    
    // 返回基准元素的索引
    return left;
};

const quickSort = (array, left, right) => {
    if (left >= right) return; // 如果数组只有一个元素或没有元素,直接返回
    
    // 获取基准元素的索引
    const mid = splitArray(array, left, right);
    
    // 对基准元素左边的子数组进行快速排序
    quickSort(array, left, mid - 1);
    
    // 对基准元素右边的子数组进行快速排序
    quickSort(array, mid + 1, right);
};

快速排序可以分成两个部分。

第一部分是拆分数组,首先会选择基准数据,然后将基准数据小的放在基准数据的左边,大于等于的放在基准数据的右边。拆分的处理是splitArray 函数,splitArray 接收三个参数,并返回拆分后的,中间下标。

拆分的过程是这样的:

  1. 获取基准元素(pivot)
  2. 初始化两个指针 left 和 right,分别指向数组的第一个元素和最后一个元素
  3. 在 left 和 right 之间进行循环比较,将小于基准元素的元素放到左边,大于等于基准元素的元素放到右边
  4. 当 left 和 right 相遇时,将基准元素放到正确的位置,返回基准元素的索引

第二部分,在拆分好了之后,将左右两边的数组继续拆分。然后重复第一部分的动作。直到拆分成只有一个元素,就停止拆分。负责第二部分的是quickSort 函数,接收三个参数。内部的逻辑是负责整个快速排序的逻辑。递归使得代码变得非常简洁,变得很容易理解

测试代码

javascript 复制代码
const data = [65, 43, 23, 2, 12, 4576, 5, 34, 23, 243, 152];

const sort = (array) => {
	const temp = [...array];
	quickSort(temp, 0, temp.length - 1);
	return temp;
};

const newArray = sort(data);
console.log(newArray);
// [
//     2,   5,   12, 23,
//    23,  34,   43, 65,
//   152, 243, 4576
// ]

新建了一个sort 函数,其中调用了 quickSort 对传入的数组进行排序。

输出结果正确,没有问题

复杂度分析

每一轮的数组划分,都会将数组从 left 到 right 遍历一遍。如果划分成了两个小组,两个小组的 left 到 right 都会遍历一遍;如果划分成了四个小组,那么四个小组的 left 到 right 都会遍历一遍。所以遍历复杂度可以看作 O(n)。

那划分多少次呢?每次的划分都将数组一分为二,所以次数大约为 O(logn) (和相同节点的满二叉树的高度相似)。

所以整体的复杂度就是 O(nlogn)

稳定性分析

javascript 复制代码
const data = [2,2,1]

稳定性就意味着相同大小的元素,在排序之后的相对位置不会发生变化。

上面的数组有两个 2,将前面一个 2 记作 2a,后面的记作 2b;left 指向下标 0,right 指向下标 2; 下面开始快速排序的过程的模拟。

首先将 2a 作为基准元素,将 1 和 2a 进行比较,1 < 2, 所以 data0 = data2;然后比较 dataleft 和 2a 的大小,此时 dataleft == 1, 所以 left ++,即 left 指向了下标 1。

继续比较 dataleft 和 2a 的大小。此时 dataleft == 1, 所以 left ++,即 left 指向了下标 2

此时 left == right =2,停止遍历。将 2a 放到 dataleft 的位置,即 data2 = 2a;

快排结束。 此时 data 中的内容是 1, 2b, 2a 。 2a 和 2b 发生了相对位置的变化 ,所以快排不稳定

总结

这篇文章分享了一种排序算法--快速排序,介绍了快速排序基本思想,以及代码实现,复杂度分析,稳定性分析。过程清晰,内容详实,是个不可多得的好文章。

你觉得这篇文章怎么样?我每天都会分享一篇算法小练习,喜欢就点赞+关注吧

相关推荐
inrichtt3 小时前
第八课时:SPI总线揭秘:四线全双工通信的奥
c语言·数据结构·stm32·单片机·嵌入式硬件
HPtiger3 小时前
数据结构——选择排序
数据结构·算法·排序算法
康实训3 小时前
老年评估仿真实训平台架构设计与老年人能力评估实训室教学落地实践
大数据·人工智能·算法·实训室·实训室建设
DongQiShanRen4 小时前
六根硬件映射(四):归属澄清、两处不一致与卷十一总表
开发语言·人工智能·算法·rust·哈希算法·集成学习
CCblandy4 小时前
雪花 ID 四个边界实测:时钟回拨重号 500 个,前端 JSON.parse 直接丢精度
后端·python·算法·性能优化·架构
持敬chijing4 小时前
白盒测试与代码审计-js登录逆向实战
javascript·网络·安全·web安全·网络安全·网络攻击模型
丑梨数据4 小时前
信创环境里跑文档工具:格式兼容与本地合规的几个坑
数据结构·人工智能·算法·决策树·排序算法
烂蜻蜓4 小时前
Pandas入门教程(四):Series数据结构——创建、索引与常用方法
数据结构·pandas
优选资源分享5 小时前
PicGo v3.0.3 新版 | 开源免费图床工具
javascript·笔记·electron
ShineWinsu5 小时前
对于JavaScript:JavaScript基础语法的解析
开发语言·前端·javascript·面试·web·基础语法·循环