🥳每日一练-快速排序-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, 所以 data[0] = data[2];然后比较 data[left] 和 2a 的大小,此时 data[left] == 1, 所以 left ++,即 left 指向了下标 1。

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

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

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

总结

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

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

相关推荐
软件开发技术深度爱好者9 分钟前
用HTML5+CSS+JavaScript庆祝国庆
javascript·css·html5
wclass-zhengge38 分钟前
数据结构篇(绪论)
java·数据结构·算法
Dylanioucn38 分钟前
【分布式微服务云原生】探索Redis:数据结构的艺术与科学
数据结构·redis·分布式·缓存·中间件
何事驚慌39 分钟前
2024/10/5 数据结构打卡
java·数据结构·算法
结衣结衣.39 分钟前
C++ 类和对象的初步介绍
java·开发语言·数据结构·c++·笔记·学习·算法
大三觉醒push亡羊补牢女娲补天版40 分钟前
数据结构之排序(5)
数据结构
TJKFYY41 分钟前
Java.数据结构.HashSet
java·开发语言·数据结构
汪子熙1 小时前
Angular 服务器端应用 ng-state tag 的作用介绍
前端·javascript·angular.js
卡皮巴拉吖1 小时前
【堆排】为何使用向下调整法建堆比向上调整法建堆更好呢?
数据结构
大二转专业3 小时前
408算法题leetcode--第24天
考研·算法·leetcode