TypeScript实现十大排序算法(五) - 快速排序

2,787 阅读2分钟

一. 快速排序的定义

快速排序(Quicksort),又称分区交换排序(partition-exchange sort),简称快排

  • 由Tony Hoare在1959年发明。
  • 快速排序使用了分治的思想,将数组划分为两个子数组,每个子数组再分别进行排序,最终实现整个数组的排序。
  • 快速排序的特点是时间复杂度较好,平均情况下为O(nlogn)。
  • 另外,快速排序是一种原地排序算法,不需要额外的存储空间。

快速排序是一种非常流行的排序算法,因为它的时间复杂度和实现方式非常优秀。

快速排序广泛应用于各种场景,如数据库、搜索引擎等,其高效的排序速度和低空间复杂度使得它成为了一种非常重要的排序算法。

快速排序的作者

二. 快速排序的流程

快速排序的思路可以分解成以下几个步骤:

  • ①首先,我们需要选择一个基准元素,通常选择第一个或最后一个元素作为基准元素。
  • ②然后,我们定义两个指针 i 和 j,分别指向数组的左右两端。
  • ③接下来,我们从右侧开始,向左移动 j 指针,直到找到一个小于或等于基准元素的值。
  • ④然后,我们从左侧开始,向右移动 i 指针,直到找到一个大于或等于基准元素的值。
  • ⑤如果 i 指针小于或等于 j 指针,交换 i 和 j 指针所指向的元素。
  • ⑥重复步骤 3-5,直到 i 指针大于 j 指针,这时,我们将基准元素与 j 指针所指向的元素交换位置,将基准元素放到中间位置。
  • ⑦接着,我们将数组分为两部分,左侧部分包含小于或等于基准元素的元素,右侧部分包含大于基准元素的元素。
  • ⑧然后,对左右两部分分别进行递归调用快速排序,直到左右两部分只剩下一个元素。
  • ⑨最终,整个数组就变得有序了。

三. 快速排序的图解

快速排序

整体流程:

快速排序

案例步骤:

快速排序

四. 快速排序的代码

下面是TypeScript实现的快速排序代码,带有详细的注释:

 // 定义快速排序函数,参数为待排序的数组
 function quickSort(array: number[]): number[] {
     // 定义辅助函数,用于排序
     function sort(left: number, right: number): void {
         // 如果左边的索引比右边的索引大,说明区间内已经没有数据,退出函数
         if (left >= right) {
             return;
         }
         // 取出基准数
         let pivot = array[left];
         // 定义两个指针
         let i = left;
         let j = right;
         // 开始排序
         while (i < j) {
             // 从右边开始搜索,直到找到比基准数小的数
             while (i < j && array[j] >= pivot) {
                 j--;
             }
             // 如果找到了,则将该数存放在左边
             if (i < j) {
                 array[i] = array[j];
                 i++;
             }
             // 从左边开始搜索,直到找到比基准数大的数
             while (i < j && array[i] <= pivot) {
                 i++;
             }
             // 如果找到了,则将该数存放在右边
             if (i < j) {
                 array[j] = array[i];
                 j--;
             }
         }
         // 将基准数存放在最终的位置上
         array[i] = pivot;
         // 递归处理基准数左边的数据
         sort(left, i - 1);
         // 递归处理基准数右边的数据
         sort(i + 1, right);
     }
     // 调用辅助函数,开始排序
     sort(0, array.length - 1);
     // 返回排序后的数组
     return array;
 }
 ​
 ​
 // 测试数据
 const testArr = [5, 2, 9, 1, 5, 6];
 // 调用插入排序函数
 const sortedArr = quickSort(testArr);
 // 打印结果
 console.log(sortedArr);

整个代码实现了快速排序的算法流程:

  1. 在数组中选择一个元素作为基准元素(通常是数组的第一个元素)
  2. 将小于等于基准元素的元素移到数组的左边,大于基准元素的元素移到数组的右边
  3. 递归地对左半部分数组和右半部分数组进行快速排序

五. 快速排序的时间复杂度

快速排序的复杂度分析需要从时间复杂度和空间复杂度两个方面来考虑。

时间复杂度: 快速排序是一种分治思想的排序算法,它的时间复杂度取决于基准数的选取。

  • 最坏情况下,每次选取的基准数为序列中的最大或最小数,导致划分的两部分长度不平均,递归的次数将会达到O(n),因此时间复杂度为O(n^2)。
  • 最优情况下,每次选取的基准数将整个序列划分成两个长度大致相等的部分,递归的次数将会达到log2n,因此时间复杂度为O(nlogn)。
  • 平均情况下,时间复杂度为O(nlogn)。

空间复杂度: 快速排序是一种原地排序算法,它不需要额外的存储空间。

  • 在递归过程中,空间复杂度仅为递归调用的栈空间,因此空间复杂度为O(logn)。

总结: 快速排序的时间复杂度为O(nlogn),空间复杂度为O(logn),是一种高效的排序算法。

六. 快速排序的总结

快速排序是一种分治算法,它的思想是通过选定一个基准值,将数组分成两个部分,左边部分的元素都小于等于基准值,右边部分的元素都大于基准值,然后再递归地对左右两个部分进行快速排序。

快速排序的时间复杂度为 O(nlogn)

  • 在最坏情况下,时间复杂度可能退化为O(n^2)。
  • 但是它的平均时间复杂度是O(nlogn)。

快速排序的空间复杂度为 O(logn)

  • 因为它需要递归调用,但是它的空间复杂度与数据的大小并不相关,所以它不会导致内存使用方面的困难。

总的来说,快速排序是一种高效的排序算法,适用于大多数的排序场景。

coderwhy公众号分享各种编程技术、生活、感悟,欢迎关注、交流、分享。