🥳每日一练-快速排序-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 发生了相对位置的变化 ,所以快排不稳定

总结

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

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

相关推荐
牛油果子哥q7 分钟前
AVL平衡树与红黑树深度精讲对比,平衡因子、四大旋转原理、着色规则、平衡策略、性能差异与面试手撕全解
数据结构·c++·面试
汉克老师29 分钟前
GESP7级C++考试语法知识(二、指数函数(3、综合练习)
c++·算法·数学建模·指数函数·gesp7级·复利
林间码客1 小时前
04 ROC曲线与AUC:从零开始手动计算
大数据·人工智能·算法
Irissgwe1 小时前
map/set/multimap/multiset 的底层逻辑与实现
数据结构·c++·算法·二叉树·stl·c·红黑树
m0_547486661 小时前
《HTML+CSS+JavaScript+Vue前端开发技术教程》全套PPT课件
javascript·css·html
IronMurphy1 小时前
【算法五十八】23. 合并 K 个升序链表
数据结构·算法·链表
思茂信息1 小时前
CST软件基于液态金属开关的方向图可重构天线
服务器·算法·重构·cst·仿真软件·电磁仿真
FliPPeDround1 小时前
告别离线 Agent:deepseek-kit 内置 Web Search,零配置联网搜索
javascript·agent·deepseek
米丘2 小时前
SSE (server-sent events)
javascript·网络协议
月疯2 小时前
PPG研究中暑的算法记录
算法