首页 > 编程语言 >排序算法-快速排序

排序算法-快速排序

时间:2024-04-13 17:33:21浏览次数:30  
标签:基准 元素 算法 数组 排序 快速 复杂度

排序算法-快速排序

一、快速排序介绍

1.1 原理介绍

快速排序(Quick Sort)是一种常用的排序算法,也是一种基于分治思想的排序算法。

快速排序的基本思想是选取一个基准元素,将数组分成两部分,使得左边部分的元素都小于等于基准元素,右边部分的元素都大于等于基准元素,然后对左右两部分分别递归进行排序,最终得到一个有序数组。

1.2 原理介绍

下面来详细介绍一下快速排序的原理和实现过程:

  • 选择基准元素
    快速排序的第一步是选择一个基准元素,一般情况下是选择数组的第一个元素或最后一个元素作为基准元素。选择基准元素的目的是将数组划分成两个部分,使得左边部分的元素都小于等于基准元素,右边部分的元素都大于等于基准元素。
  • 划分数组
    在选择了基准元素之后,需要将数组划分成两部分。具体方法是使用两个指针 i 和 j 分别从数组的左右两端开始扫描,当 i 指向的元素大于等于基准元素时,停止移动,当 j 指向的元素小于等于基准元素时,停止移动,然后交换 i 和 j 指向的元素,继续移动指针。当 i 和 j 相遇时,将基准元素与 i 指向的元素交换位置,这样就完成了一次划分。
  • 递归排序
    划分数组之后,将左右两部分分别递归进行排序,直到每个部分只剩下一个元素或空数组为止。递归排序的过程中,需要重复执行以上两个步骤,即选择基准元素和划分数组。
  • 合并数组
    在递归排序完成之后,需要将左右两部分合并成一个有序数组。由于左右两部分都已经有序,可以使用归并排序的思想来合并数组。

示例讲解

下面举一个例子来说明快速排序的过程:

  1. 原数组:[3, 5, 1, 9, 7, 2, 8, 4, 6]
  2. 选择基准元素 3,分成左半部分 [1, 2] 和右半部分 [5, 9, 7, 8, 4, 6]
  3. 对左半部分 [1, 2] 递归调用快速排序算法,得到有序数组 [1, 2]
  4. 对右半部分 [5, 9, 7, 8, 4, 6] 选择基准元素 5,分成左半部分 [4] 和右半部分 [9, 7, 8, 6]
  5. 对左半部分 [4] 递归调用快速排序算法,得到有序数组 [4]
  6. 对右半部分 [9, 7, 8, 6] 选择基准元素 9,分成左半部分 [7, 8, 6] 和右半部分 []
  7. 对左半部分 [7, 8, 6] 选择基准元素 7,分成左半部分 [6] 和右半部分 [8]
  8. 对左半部分 [6] 递归调用快速排序算法,得到有序数组 [6]
  9. 对右半部分 [8] 递归调用快速排序算法,得到有序数组 [8]
  10. 将左半部分 [6]、基准元素 7 和右半部分 [8] 拼接起来,得到有序数组 [6, 7, 8]
  11. 将左半部分 [4]、基准元素 5 和右半部分 [6, 7, 8, 9] 拼接起来,得到有序数组 [4, 5, 6, 7, 8, 9]
  12. 将左半部分 [1, 2]、基准元素 3 和右半部分 [4, 5, 6, 7, 8, 9] 拼接起来,得到有序数组 [1, 2, 3, 4, 5, 6, 7, 8, 9]

1.3复杂度

  • 时间复杂度:

    快速排序的平均时间复杂度为 O(nlogn),其中 n 表示要排序的数组的长度。
    在最坏情况下,即每次选择的基准元素都是当前数组中最小或最大的元素,递归树的深度将达到 n,此时的时间复杂度为 O(n^2)。但是,快速排序的平均时间复杂度远远优于最坏情况下的时间复杂度。
    快速排序的优势在于它是一种原地排序算法,即不需要额外的存储空间,只需要通过交换数组中的元素来实现排序。这使得快速排序在实际应用中表现出色,被广泛使用。

  • 空间复杂度:

    快速排序的空间复杂度为 O(logn) 至 O(n),其中 n 表示要排序的数组的长度。
    在递归调用快速排序算法时,需要使用递归栈来保存每一层递归的状态。
    在最坏情况下,即每次选择的基准元素都是当前数组中最小或最大的元素,递归树的深度将达到 n,此时的空间复杂度为 O(n)。但是,在平均情况下,递归树的深度通常为 O(logn),因此空间复杂度为 O(logn)。另外,快速排序是一种原地排序算法,即不需要额外的存储空间,只需要通过交换数组中的元素来实现排序。因此,快速排序的空间复杂度在最优情况下为 O(1)。

1.4 应用场景

快速排序是一种高效的排序算法,在实际应用中被广泛使用。以下是一些快速排序的应用场景:

  1. 排序大规模数据:快速排序的时间复杂度为 O(nlogn),比其他常见的排序算法如冒泡排序、选择排序和插入排序等更快,因此适用于需要处理大规模数据的场景。

  2. 搜索数据:快速排序可以对数据进行排序,使得搜索数据时可以更快速地定位到目标数据,因此适用于需要频繁搜索数据的场景。

  3. 数据压缩:快速排序可以将相似的数据放在一起,从而提高数据的压缩率,因此适用于需要进行数据压缩的场景。

  4. 数据库查询:快速排序可以对数据库中的数据进行排序,从而提高查询效率,适用于需要频繁查询数据库的场景。

  5. 数组去重:快速排序可以将数组中相同的元素放在一起,从而方便去重操作,适用于需要进行数组去重的场景。

1.5 优缺点

优点:
快速排序是一种高效的排序算法,具有以下优点:

  • 时间复杂度低:快速排序的平均时间复杂度为 O(nlogn),比其他常见的排序算法如冒泡排序、选择排序和插入排序等更快。

  • 原地排序:快速排序是一种原地排序算法,即不需要额外的存储空间,只需要通过交换数组中的元素来实现排序。

  • 分治思想:快速排序采用分治思想,将问题分解为若干个子问题进行求解,从而简化了问题的复杂度。

  • 可以进行原地去重操作:快速排序可以将数组中相同的元素放在一起,从而方便去重操作。

缺点:

但是,快速排序也存在一些缺点:

  • 最坏情况下的时间复杂度较高:在最坏情况下,即每次选择的基准元素都是当前数组中最小或最大的元素,递归树的深度将达到 n,此时的时间复杂度为 O(n^2)。

  • 对于小规模数据排序效率低:当要排序的数据规模较小的时候,快速排序的效率不如其他简单的排序算法,如插入排序和冒泡排序等。

  • 选择基准元素的难度:选择基准元素的方式会影响快速排序的性能,如果每次选择的基准元素都是当前数组中的最小或最大元素,将会导致快速排序的性能退化。

  • 不稳定性:快速排序是一种不稳定的排序算法,即在排序过程中相同的元素可能会被交换位置,从而导致相同元素的相对位置发生变化。

二、代码实现

python实现

def quick_sort(arr):
    """
    快速排序算法的实现函数
    Parameters:
        arr (list): 要排序的数组
    Returns:
        list: 排序后的数组
    """
    # 如果数组长度小于等于1,则直接返回
    if len(arr) <= 1:
        return arr
 
    # 选择基准元素
    pivot = arr[0]
 
    # 分割数组
    left = [x for x in arr[1:] if x <= pivot]
    right = [x for x in arr[1:] if x > pivot]
 
    # 递归调用快速排序算法,并将分割后的数组合并起来
    return quick_sort(left) + [pivot] + quick_sort(right)

测试

import random
 
# 生成随机数组
arr = [random.randint(0, 100) for _ in range(10)]
print("原始数组:", arr)
 
# 对数组进行快速排序
arr_sorted = quick_sort(arr)
print("排序后数组:", arr_sorted)
 
# 验证排序结果是否正确
assert arr_sorted == sorted(arr), "排序结果不正确"
print("排序结果正确")

【本文转载】
原文链接:https://blog.csdn.net/weixin_36755535/article/details/131145158

标签:基准,元素,算法,数组,排序,快速,复杂度
From: https://www.cnblogs.com/zx-demo/p/18133119

相关文章

  • 算法
    算法1、定义算法是解决特定问题或执行特定任务的一系列明确定义的步骤或指令。它是一个用于解决问题的有序集合,通过一系列的操作来转换输入数据为所需的输出结果。2、特点算法通常具有以下特征:有限性(Finiteness):算法必须在有限的步骤内结束,不会无限循环或持续执行下去。确定......
  • 排序算法
    排序算法1.排序算法定义:排序算法是一种将数据元素按特定顺序(通常是升序或降序)排列的算法。排序是计算机科学中最基本的操作之一,用于数据组织和优化搜索算法等。2、排序算法分类快速排序归并排序堆排序冒泡排序快速排序:快速排序是一种高效的分治排序算法,通过选定一个'......
  • P1155 [NOIP2008 提高组] 双栈排序
    P1155[NOIP2008提高组]双栈排序有思维的二分图染色题。对于“双”类的题目,我们通常分开考虑单个时的性质。对于一个栈,有一个基本的定理:若出现\(i<j<k\),有\(a_k<a_i<a_j\),那么一定不合法,即没有合法的出栈顺序使之有序。对于两个栈,我们相当于把序列分成两部分,使每部分之间......
  • 记录协助Javaer硬件快速开发过程之Web技术栈对接施耐德网络IO网关
    前一段时间有个Java技术栈的朋友联系到我,需要快速对接现有的无人值守称重系统,这里的对接是指替代现有系统,而非软件层面的对接,也就是利用现有的硬件开发一套替代现有软件的自动化系统。主要设备包括地磅秤、道闸、红外对射传感器、摄像头、小票打印、LED显示屏等等,全程使用LED显示......
  • 最小生成树 Kruskal 算法
    Kruskal算法edge存储边起点、终点、边权fa[x]存储x的父节点1、先初始化父节点2、按边的权排序(贪心思想)3、如果不在同一集合内,把这条边加入最小生成树,并且合并两个集合,反之就跳过4、最后根据连接的点是否是顶点的个数减一确定能否生成最小生成树如下图,红色表示取的边和次......
  • bufDataSet排序
    https://wiki.lazarus.freepascal.org/How_to_write_in-memory_database_applications_in_Lazarus/FPC SortingDBGridonTitleClickeventforTBufDataSetIfyouwishtoenableconsecutiveascendinganddescendingsortingofaDBGridshowingsomedatafromTBufD......
  • 数据分享|R语言逻辑回归、Naive Bayes贝叶斯、决策树、随机森林算法预测心脏病|附代码
    全文链接:http://tecdat.cn/?p=23061最近我们被客户要求撰写关于预测心脏病的研究报告,包括一些图形和统计输出。这个数据集可以追溯到1988年,由四个数据库组成。克利夫兰、匈牙利、瑞士和长滩。"目标"字段是指病人是否有心脏病。它的数值为整数,0=无病,1=有病数据集信息:目标:主......
  • 最短路算法(Dijkstra + SPFA + Floyd)
    最短路算法(Dijkstra+SPFA+Floyd)Dijkstra算法1.算法基本介绍Dijkstra算法通常是求解单源最短路中最快的算法,但它无法处理存在负权边的情况(原因在正确性证明中)。Dijkstra本质上是一种贪心算法,通过不断调整每个点的“当前距离”最终得到最优结果,其实后面要讲到的几种算法也大......
  • C++算法题解 - 递归实现排列型枚举 - 递归法 (图文) (递归搜索树)
    题目:递归实现排列型枚举把1∼n这n个整数排成一行后随机打乱顺序,输出所有可能的次序。输入格式一个整数n。输出格式按照从小到大的顺序输出所有方案,每行1个。首先,同一行相邻两个数用一个空格隔开。其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。数据......
  • 常见的排序算法——冒泡排序(二)
    本文记述了冒泡排序微小改动的基本思想和一份参考实现代码,并在说明了算法的性能后用随机数据进行了验证。◆思想更少的比较可以节省一定的时间,此改动可以减少更小范围的比较。(把水平陈列的数组逆时针旋转90°后,有助于理解后续的内容。)将包含顶层以下的所有元素作为待排序范围......