飞道的博客

Python 编程1000例(26):排序算法——快速排序法

281人阅读  评论(0)

本系列文章通过 1000(一篇文章表示 1 个实例) 个实例 ,为读者提供较为详细的练习题目,以便读者举一反三,深度学习。本系列的文章涉及到 Python 知识点包括:Python 语言基础、运算符和表达式、语句和程序结构、列表和元组、字典和集合、字符串、正则表达式、函数、面向对象编程、模块和包、异常处理和程序调试、文件和目录操作、数据库编程、界面编程、网络编程、WEB 编程、进程和线程、网络爬虫、游戏编程等知识点,由易到难,由浅入深,一步步打下坚实的编程基础。

本系列文章涉及的算法包括搜索、回溯、递归、排序、迭代、贪心、分治和动态规划等,涉及的数据结构包括字符串、列表、指针、区间、队列、矩阵、堆栈、链表、哈希表、线段树、二叉树、二叉搜索树和图结构等。

本系列文章是笔者为适应当前教育改革的创新要求,更好地践行语言类课程,满足实践教学与创新能力培养的需要,阅读大量书籍、各大互联网公司的面试算法、LintCode、LeetCode、九章算法和结合笔者近几年项目经验编写的系列文章,精选了 1000 个趣味性、实用性强的应用实例,从不同难度、不同算法、不同类型和不同数据结构等方面,将实际算法进行总结,希望为 Python 编程人员抛砖引玉。由于笔者经验与水平有限,博文中疏漏及不妥之处在所难免,衷心地希望各位读者在评论区多提宝贵意见及具体的修改建议,以便笔者进一步修改和完善。

一、快速排序法

快速排序法又称为分割交换法,它是冒泡排序法的一种改进。它的基本思想是:先在数据中找一个虚拟的中间值,并按此中间值将所有打算排序的数据分为两部分。其中,小于中间值的数据放在左边,大于中间值的数据放在右边,再用同样的方式处理左、右两边的数据,直到排序完成。操作的步骤如下:

假设有n项数据,数据值 用K1,K2,…,Kn 来表示。

  1. 先在数据中假设一个虚拟中间值K(为了方便,一般取第一个位置上的数)。
  2. 从左向右查找数据Ki,使得Ki>K,Ki的位置数记为i。
  3. 从右向左查找数据Kj,使得Kj<K,Kj的位置数记为j。
  4. 若i<j,那么数据Ki与Kj交换,并回到步骤(2)、(3)。
  5. 若i≥j,那么数据K与Kj交换,并以j为基准点分割成左右两部分,然后针对左右两部分再进行步骤1~步骤5,直到左半边数据等于右半边数据为止。

快速排序法最后的结果也有两种形式,即递增数列和递减数列。接下来通过一组数据来演示快速排序法的排序原理。例如,有这样一组数据:6,1,2,7,9,3,4,5,10,8,如下图所示:

按照递增进行排序,步骤如下:

步骤1:取原始值的第一个数6为虚拟中间值,即K=6;然后从左向右查找值大于6的数,即数值7,位置为i,即i=4;再从右向左查找值小于6的数,即数值5,位置是j,即j=8,如下图所示:

步骤2:i<j,因此交换Ki(数值7)和Kj(数值5)的位置,完成第一次排序结果。然后再从左向右查找值大于6的数,即数值9,位置为i,即i=5;再从右向左查找值小于6的数,即数值4,位置为j,即j=7,如下图所示:

步骤3:i<j,因此交换Ki(数值9)和Kj(数值4)的位置,完成第二次排序。然后再从左向右查找值大于6的数,即数值9,位置为i,即i=7;再从右向左查找值小于6的数,即数值3,位置是j,即j=6,如下图所示:

步骤4:i>j,因此交换虚拟中间值K(数值6)和Kj(数值3)的位置,完成第三次排序。此时,发现6的左半边都是小于6的数,右半边都是大于6的数,虚拟中间值6变成了真正的中间值,如下图所示:

步骤5:对中间值6的左半边数据进行排序,中间值和右半边数据暂时可以忽略。在左半边取虚拟中间值K=3,从左向右查找大于3的值,即数值5,位置为i,即i=4;再从右向左查找小于3的值,即数值2,位置为j,即j=3。如下图所示:

步骤6:i>j,因此需要交换K(数值3)和Kj(数值2)的值,如下图所示。此时虚拟中间值变成了真正的中间值。小于3的都在中间值3的左半边,大于3的都在中间值3的右半边。

步骤7:接下来对中间值为3的左、右两侧排序,经过排序之后,最终排序结果如下图所示:

步骤8:此时,整组数据的左半边已经完成排序,接下来对右半边进行排序,这次忽略已经排序好的左半边和中间值6。取右半边第一个位置的数为虚拟中间值K(数值9),然后从左向右找大于9的值,即数值10,位置为i,即i=9;再从右向左找小于9的值,即数值8,位置为j,即j=10。如下图所示:

步骤9:i<j,因此交换Ki(数值10)和Kj(数值8)的位置。然后再从左向右查找大于9的值,即数值10,位置为i,即i=10;再从右向左找小于9的值,即数值8,位置为j,即j=9。如下图所示:

步骤10:i>j,因此交换Kj(数值8)和虚拟中间值(数值9)的值,此时,虚拟中间值变成为真正的中间值,如下图所示:

步骤11:以中间值为9的左右两侧进行排序,最后完成右半边排序,如下图所示:

结合左半边排序和右半边排序,最终的结果如下图所示:

至此,完成排序。

二、实例:使用快速排序法进行递增排序

使用快速排序法为列表:6,1,2,7,9,3,4,5,10,8,进行递增排序。具体代码如下:

def quick(data, start, end):  # 定义快速排序法函数
    if start > end:  # 如果开始值大于结束值
        return  # 直接退出程序
    i, j = start, end
    result = data[start]  # 取虚拟中间值
    while True:  # 循环
        while j > i and data[j] >= result:  # 从右向左找,找到的数比虚拟中间值小就停止循环
            j = j - 1  # 从右向左找,位置每次-1
        while i < j and data[i] <= result:  # 从左向右找,找到的数比虚拟中间值大就停止循环
            i += 1  # 从左向右找,位置每次+1
        if i < j:  # i和j都停止,找到对应的位置,判断i<j
            data[i], data[j] = data[j], data[i]  # 交换位置i和j对应的数值
        elif i >= j:  # 判断i>=j
            # 交换虚拟中间值和j位置上的数,此时虚拟中间值变成真正中间值
            data[start], data[j] = data[j], data[start]
            break  # 完成第一次排序,此时以中间值分左右两侧
    quick(data, start, i - 1)  # 调用快速排序函数,再快速排序左半边数据
    quick(data, i + 1, end)  # 调用快速排序函数,再快速排序右半边数据


data = [6, 1, 2, 7, 9, 3, 4, 5, 10, 8]  # 定义列表并初始化
print("原始数据为:")
print(data)  # 输出原始数据
print("--------------------------------")
quick(data, 0, (len(data) - 1))  # 调用快速排序,数据从位置0开始,到数据长度-1为止
print("排序之后的数据为:")
print(data)  # 输出排序后数据
print("--------------------------------")

程序运行结果如图所示:

三、练习:入职年限排名

例如,某公司的6名职员入职年限分别是:1,3,15,20,5,4。利用快速排序法给这些职员入职年限按照从高到低顺序排序,具体代码如下:

def quick(data, start, end):  # 定义快速排序法函数
    if start > end:  # 如果开始值大于结束值
        return  # 直接退出程序
    i, j = start, end
    result = data[start]  # 取虚拟中间值
    while True:  # 循环
        while j > i and data[j] <= result:  # 从右向左找,找到的数虚拟中间值大就停止循环
            j = j - 1  # 从右向左找,位置每次-1
        while i < j and data[i] >= result:  # 从左向右找,找到的数虚拟中间值小就停止循环
            i += 1  # 从左向右找,位置每次+1
        if i < j:  # i和j都停止,找到对应的位置,判断i<j
            data[i], data[j] = data[j], data[i]  # 交换位置i和j对应的数值
        elif i >= j:  # 判断i>=j
            # 交换虚拟中间值和j位置上的数,此时虚拟中间值变成真正中间值
            data[start], data[j] = data[j], data[start]
            break  # 完成第一次排序,此时以中间值分左右两侧
    quick(data, start, i - 1)  # 调用快速排序函数,再快速排序左半边数据
    quick(data, i + 1, end)  # 调用快速排序函数,再快速排序右半边数据


data = [1, 3, 15, 20, 5, 4]  # 定义列表并初始化
print("六名职员入职年限如下:")
print(data)  # 输出原始数据
print("→→→→→→→→→→→→→→→→→→→→→")
quick(data, 0, (len(data) - 1))  # 调用快速排序,数据从位置0开始,到数据长度-1为止
print("从高到低排序之后的入职年限如下:")
print(data)  # 输出排序后数据
print("→→→→→→→→→→→→→→→→→→→→→")

程序运行结果如图所示:

感谢您阅读本篇博文,希望本文能成为您编程路上的领航者。祝您阅读愉快!


    好书不厌读百回,熟读课思子自知。而我想要成为全场最靓的仔,就必须坚持通过学习来获取更多知识,用知识改变命运,用博客见证成长,用行动证明我在努力。
    如果我的博客对你有帮助、如果你喜欢我的博客内容,请 点赞评论收藏 一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。
 编码不易,大家的支持就是我坚持下去的动力。点赞后不要忘了 关注 我哦!


转载:https://blog.csdn.net/xw1680/article/details/115986606
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场