快速排序算法及其时间复杂度分析

综述

快速排序算法是一种高效的排序算法,它采用了分治法的思想来进行排序。在快速排序中,我们选取一个元素作为基准值,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

示例

1. 初始状态

假设我们有一个无序的数组 [5, 3, 8, 6, 9, 2, 7]

2. 选择基准值

在这个例子中,我们选择数组的第一个元素 5 作为基准值。

3. 划分数组

将数组中比基准值小的元素放在它的左边,比基准值大的元素放在它的右边。这一步也称为分区操作。

分区后的数组为:[2, 3, 5, 6, 9, 8, 7]

4. 递归排序子数组

递归地对基准值左边的子数组 [2, 3] 和右边的子数组 [6, 9, 8, 7] 进行快速排序。即重复前面123的步骤

5. 合并有序子数组

当递归到子数组长度为10时,停止递归。然后,将两个有序子数组合并成一个有序数组。

合并后的数组为:[2, 3, 5, 6, 7, 8, 9]

代码

以下是代码示例

python代码

def quick_sort(arr):
    """
    这段代码实现的是经典快速排序算法,其基本思想是选择一个基准元素,
    将列表分成两个子数组,小于等于基准的元素放在左边,大于基准的元素放在右边,
    然后递归地对左右两个子列表进行排序。
    :param arr: 原排序前无序列表
    :return: 新排序后有序列表
    """
    # 递归终止条件:列表长度小于或等于1,直接返回列表
    if len(arr) <= 1:
        return arr
    # 选择基准元素,这里选择中间元素
    pivot = arr[len(arr) // 2]
    # 创建三个列表,分别存储小于、等于、大于基准的元素
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    # 递归调用快速排序,将小于和大于基准的元素分别排序,再拼接中间元素,返回结果
    return quick_sort(left) + middle + quick_sort(right)


if __name__ == '__main__':
    arr = [5, 3, 8, 6, 9, 2, 7]
    print(quick_sort(arr))

java代码

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = new int[]{5, 3, 8, 6, 9, 2, 7};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));
    }

    /***
     * 这段代码实现的是经典快速排序算法,其基本思想是选择一个基准元素,
     * 将数组分成两个子数组,小于等于基准的元素放在左边,大于基准的元素放在右边,
     * 然后递归地对左右两个子数组进行排序。
     * 其中partition函数用于将小于等于基准的元素放在左边,大于基准的元素放在右边,并返回基准的索引。
     * @param arr 原排序前无序列表
     * @param left arr的起始索引
     * @param right arr的结束索引
     */
    private static void quickSort(int[] arr, int left, int right) {
        // 递归终止条件:左指针大于等于右指针,返回
        if (left >= right) {
            return;
        }
        // 选择基准元素,这里选择最右边的元素
        int pivotIndex = partition(arr, left, right);
        // 递归调用快速排序,对基准左边和右边的子数组分别进行排序
        quickSort(arr, left, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, right);
    }

    private static int partition(int[] arr, int left, int right) {
        // 选择基准元素,这里选择最右边的元素
        int pivot = arr[right];
        int i = left - 1;
        // 遍历数组,将小于等于基准的元素放在左边,大于基准的元素放在右边
        for (int j = left; j < right; j++) {
            if (arr[j] <= pivot) {
                i++;
                // 交换元素位置
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        // 将基准放在正确的位置上
        int temp = arr[i + 1];
        arr[i + 1] = arr[right];
        arr[right] = temp;
        // 返回基准的索引
        return i + 1;
    }
}

时间复杂度分析

下面分别从最好、平均和最坏情况来介绍快速排序的时间复杂度。

1. 最好情况- O(nlogn)

当每次划分都能将数组分成两个等长的子数组时,快速排序的时间复杂度为 O(nlogn)。这是因为每次划分都能将数组分成两个等长的子数组,所以递归树的深度为 logn,而每个节点都需要进行一次比较和一次交换操作,所以总的时间复杂度为 O(nlogn)

2. 最坏情况- O(n^2)

当每次划分都不能将数组分成两个等长的子数组时,快速排序的时间复杂度为 O(n^2)。这是因为每次划分只能将数组分成一个比原数组更小的子数组和一个比原数组更大的子数组,所以递归树的深度为 n,每个节点都需要进行一次比较和一次交换操作,所以总的时间复杂度为 O(n^2)

3. 平均情况- O(nlogn)

快速排序的平均时间复杂度为 O(nlogn)。这是因为每次划分都能将数组分成两个等长的子数组的概率是存在的,所以快速排序的平均时间复杂度为 O(nlogn)

总结

快速排序的时间复杂度取决于基准值的选择,最好情况是 O(nlogn),最坏情况是 O(n^2)。然而,在实际应用中,通过随机化选择基准值或使用其他技巧,可以使得快速排序在大多数情况下表现良好。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python中常用的排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序和堆排序等。每个排序算法时间复杂度不同。 冒泡排序的时间复杂度为O(n^2)。每次比较相邻的两个元素,如果顺序错误,则交换位置,重复这个过程直到整个数组排序完成。由于需要多次遍历数组,所以时间复杂度较高。 选择排序的时间复杂度也为O(n^2)。每次从未排序的部分中选择最小的元素,然后与未排序部分的第一个元素交换位置。重复这个过程直到整个数组排序完成。 插入排序的时间复杂度为O(n^2)。将未排序的元素逐个插入已排序的部分中的正确位置。具体操作是从后往前比较,如果当前元素比前一个元素小,则交换位置,重复这个过程直到整个数组排序完成。 快速排序的平均时间复杂度为O(nlogn)。通过选择一个基准元素,将数组分为两个子数组,其中一个子数组的所有元素小于基准元素,另一个子数组的所有元素大于基准元素。然后对两个子数组分别递归地进行快速排序,最后合并两个子数组得到有序数组。 归并排序的时间复杂度也为O(nlogn)。通过将数组递归地拆分成更小的子数组,然后对子数组进行排序,最后将排好序的子数组合并成一个有序数组。 堆排序的时间复杂度为O(nlogn)。首先将数组构建成一个最大堆或最小堆,然后不断地将堆顶元素与堆的最后一个元素交换位置,并重新调整堆,重复这个过程直到整个数组排序完成。 综上所述,Python中常用的排序算法及其时间复杂度如上所示。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [常见排序算法及其对应的时间复杂度和空间复杂度](https://blog.csdn.net/weixin_39734493/article/details/110335437)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [python实现排序算法 时间复杂度、稳定性分析 冒泡排序、选择排序、插入排序、希尔排序](https://blog.csdn.net/weixin_39852276/article/details/110335432)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值