数据结构和算法-排序算法-快速排序

##################     快速排序        #######################

"""

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。

步骤为:
1,挑选基准值:从数列中挑出一个元素,称为"基准"(pivot);
2,分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。
在这个分割结束之后,对基准值的排序就已经完成;
3,递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。
递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。

"""

##################     快速排序        #######################

"""
alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
第一种实现
通过两个游标,left,right ,把第一个元素作为基准值,

第一轮,54作为基准值,left游标指向26,right游标指向20
退出条件是low<=right
left指向的都要比54小,否则就停住,
right指向的都要比54大,否则就停住,
然后左右交换,继续下去,直到满足退出条件,第一轮结束,

第二轮,继续执行相同的操作,递归执行,

一直递归结束,进行合并

"""

代码:

def quick_sort(alist, first, last):
    """快速排序"""
    if first >= last:  # 递归的退出条件
        return
    mid_value = alist[first]
    low = first  #
    high = last
    while low < high:  # 记住是交替执行的,两个游标重合的时候就是退出的时候,
        while low < high and alist[high] >= mid_value:
            high -= 1
        alist[low] = alist[high]
        while low < high and alist[low] < mid_value:
            low += 1
        alist[high] = alist[low]
    # 循环退出之后,low和high是相等的,
    alist[low] = mid_value  # 将基准元素放到该位置,
    # 对基准元素左边的子序列进行快速排序
    quick_sort(alist, first, low - 1)  # first :0  low -1 原基准元素靠左边一位
    # 对基准元素右边的子序列进行快速排序
    quick_sort(alist, low + 1, last)  # low+1 : 原基准元素靠右一位  last: 最后

if __name__ == ‘__main__‘:
    alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    quick_sort(alist, 0, len(alist) - 1)
    print(alist)

最优时间复杂度分析

"""

看代码不好分析了,看逻辑
1,第一轮复杂度就是n,
2,第二轮复杂度也是n,
3,多少轮结束?要取对数,logn,
最优时间复杂度:总的就是O(nlogn),最好的情况就是每一个值都是在中间,
最坏时间复杂度,O(n^2)
"""

##################     快速排序        #######################

# 第二个版本

# 这个方法是算法导论里面的,比较上一种方法,在于分片的过程不同,只用了一次循环,并且一趟就完成了分片,比较之下,代码要简洁的多,

# 这个函数是分成两部,返回一个分割下标,这个下标就是把大于基准值的放到一边,小于基准值的放到一边,
# arr = [10, 7, 8, 9, 2, 1, 5]

def partition(arr, low, high):
    i = (low - 1)  # 最小元素索引
    pivot = arr[high]  # 把最右边最为一个分割点,

    for j in range(low, high):
        # 当前元素小于或等于 pivot
        if arr[j] <= pivot:  # 遍历每一个列表元素和基准值比较
            i = i + 1  # 第一次触发就是变成0,表示第一个元素是最小值,
            arr[i], arr[j] = arr[j], arr[i]  # 因为上一步表示了第一个元素是最小值所以要和 i 替换,
    # 上面循环退出的时候:i =2  列表: [2,1,8,9,10,7,5]
    arr[i + 1], arr[high] = arr[high], arr[i + 1]  # high = 5 这个时候high就是所谓的基准值 i+1 就是8了,
    # 替换之后,就是基准值的左边都小于基准值,右边都大于基准值了,
    return (i + 1)  # 返回这个i+1 就是所谓的基准值分割点的索引了,

# arr[] --> 排序数组
# low  --> 起始索引
# high  --> 结束索引

# 快速排序函数
def quickSort(arr, low, high):
    if low < high:
        pi = partition(arr, low, high)

        quickSort(arr, low, pi - 1)
        quickSort(arr, pi + 1, high)

arr = [10, 7, 8, 9, 2, 1, 5]
n = len(arr)
quickSort(arr, 0, n - 1)
print("排序后的数组:")
for i in range(n):
    print("%d" % arr[i])

##################     快速排序        #######################

"""
先来看一个 我更想称之为伪快排的快排代码:
这段代码最关键的是pivot这个参数,这段代码里取序列的第一个元素,然后以这个元素为分组的基准,利用列表解析式使得它左边的值都比它小,右边的值都比它大。然后再分别对这些序列进行递归排序。
def quicksort(arr):
    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 quicksort(left) + middle + quicksort(right)
print(quicksort([3, 6, 8, 19, 1, 5]))  # [1,3, 5, 6, 8, 19]
 
def quick_sort(b):
    """快速排序"""
    if len(b) < 2:
        return arr
    # 选取基准,随便选哪个都可以,选中间的便于理解
    mid = arr[len(b) // 2]
    # 定义基准值左右两个数列
    left, right = [], []
    # 从原始数组中移除基准值
    b.remove(mid)
    for item in b:
        # 大于基准值放右边
        if item >= mid:
            right.append(item)
        else:
            # 小于基准值放左边
            left.append(item)
    # 使用迭代进行比较
    return quick_sort(left) + [mid] + quick_sort(right)

这段代码虽然短小利于理解,但是其效率很低,主要体现在以下方面:
分组基准的选取过于随便,不一定可以取到列表的中间值
空间复杂度大,使用了两个列表解析式,而且每次选取进行比较时需要遍历整个序列。
若序列长度过于小(比如只有几个元素),快排效率就不如插入排序了。
递归影响性能,最好进行优化。

"""

##################     快速排序        #######################

"""
特点
稳定性:快排是一种不稳定排序,比如基准值的前后都存在与基准值相同的元素,那么相同值就会被放在一边,这样就打乱了之前的相对顺序

比较性:因为排序时元素之间需要比较,所以是比较排序

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

空间复杂度:排序时需要另外申请空间,并且随着数列规模增大而增大,其复杂度为:O(nlogn)

归并排序与快排 :归并排序与快排两种排序思想都是分而治之,但是它们分解和合并的策略不一样:归并是从中间直接将数列分成两个,而快排是比较后将小的放左边大的放右边,所以在合并的时候归并排序还是需要将两个数列重新再次排序,而快排则是直接合并不再需要排序,所以快排比归并排序更高效一些,可以从示意图中比较二者之间的区别。

快速排序有一个缺点就是对于小规模的数据集性能不是很好。

"""

##################     快速排序        #######################

##################     快速排序        #######################

原文地址:https://www.cnblogs.com/andy0816/p/12348378.html

时间: 2024-10-12 16:00:57

数据结构和算法-排序算法-快速排序的相关文章

数据结构与算法-排序算法-partial

前言 都什么时代了,还写排序算法的总结? 原因有二.一是别人的精彩永远是别人的,你只有鼓掌的份儿:有些事情实际动手去做了才会有所体会. 二是排序算法是一类基础类的算法,不光是IT从业者真正入门的门槛,也是一些高级算法的关键部分或算法评估的benchmark. 计划说明的算法内容有哪些?  算法的思想.Java代码实现和平均算法复杂度.算法运行完整示例. 参考文献有哪些? wiki[EB/OL] Shaffer C. A. Data Structure and Algorithm Analysis

数据结构和算法-排序算法-冒泡排序

##################     排序算法        ###################### """ 排序算法, 我们想要把线性表中的无序序列,排成有序序列,的算法,就是排序算法, 排序算法的稳定性 举例:假设对下面的元组要以他们的第一个数字来排序. (4, 1) (3, 1) (3, 7)(5, 6) 如果你排序之后,(3, 1) (3, 7)和原来的顺序一样,就是稳定的,否则就是不稳定的, (3, 1) (3, 7) (4, 1) (5, 6) (维

【数据结构】常用排序算法(包括:选择排序,堆排序,冒泡排序,选择排序,快速排序,归并排序)

直接插入排序: 在序列中,假设升序排序 1)从0处开始. 1)若走到begin =3处,将begin处元素保存给tmp,比较tmp处的元素与begin--处元素大小关系,若begin处<begin-1处,将begin-1处元素移动到begin:若大于,则不变化.再用tmp去和begin--处的元素用同样的方法去作比较,直至begin此时减少到数组起始坐标0之前结束. 3)以此类推,依次走完序列. 时间复杂度:O() 代码如下: //Sequence in ascending order  voi

(2)Java数据结构--二叉树 -和排序算法实现

=== 注释:此人博客对很多个数据结构类都有讲解-并加以实例 Java API —— ArrayList类 & Vector类 & LinkList类Java API —— BigDecimal类Java API —— BigInteger类Java API —— Calendar类Java API —— DateFormat类Java API —— Date类Java API —— HashMap类 & LinkedHashMap类Java API —— JDK5新特性Java

算法和数据结构~各位排序算法的介绍与实现(C#)

排序是指将元素集合按照规定的顺序排列.通常有两种排序方法,升序排列和降序排列.例如,对整数集{5,2,7,1}进行升序排列,结果为{1,2,5,7},对其进行降序排列结果为{7,5,2,1}.总的来说,排序的目的是使数据能够以更有意义的形式表现出来.虽然排序最显著的应用是排列数据以显示它,但它往往可以用来解决其他的问题,特别是作为某些已成型算法的一部分.      总的来说,排序算法分为两大类:比较排序和线性时间排序.比较排序依赖于比较和交换来将元素移动到正确的位置上.令人惊讶的是,并不是所有的

【数据结构】选择排序算法示例

基本选择排序编辑 排序算法即解决以下问题的算法: 输入 n个数的序列<a1,a2,a3,...,an>. 输出 原序列的一个重排<a1*,a2*,a3*,...,an*>:,使得a1*<=a2*<=a3*<=...<=an* 排序算法有很多,包括插入排序,冒泡排序,堆排序,归并排序,选择排序,计数排序,基数排序,桶排序,快速排序等.插入排序,堆排序,选择排序,归并排序和快速排序,冒泡排序都是比较排序,它们通过对数组中的元素进行比较来实现排序,其他排序算法则是

数据结构与算法——排序算法

常见排序算法主要有: 插入排序(直接插入排序.希尔排序) 选择排序(直接选择排序.堆排序) 交换排序(冒泡排序.快速排序) 归并排序 基数排序 外部排序 一.直接插入排序 算法思想:在一个待排序列中,从第二个元素开始,依次进行排序,每次都将待排序元素从后往前,依次与前面的元素进行比较,从而将带排序元素移动到一个合适的位置,直到最后一个待排序元素移动到合适位置,则排序完成. 算法特点:最好情况下时间复杂度O(n),最坏情况下时间复杂度O(n2),稳定排序算法 二.希尔排序 希尔排序算法基础:待排序

php 实现冒泡算法排序、快速排序、选择排序,插入排序

许多人都说 算法是程序的核心,一个程序的好于差,关键是这个程序算法的优劣.作为一个初级phper,虽然很少接触到算法方面的东西 .但是对于冒泡排序,插入排序,选择排序,快速排序四种基本算法,我想还是要掌握的.下面是我按自己的理解,将四个方法分析一遍. 需求:分别用 冒泡排序法,快速排序法,选择排序法,插入排序法将下面数组中 的值按照从小到的顺序进行排序.  $arr(1,43,54,62,21,66,32,78,36,76,39); 1. 冒泡排序法   *     思路分析:法如其名,就是像冒

数据结构复习之排序算法的总结回顾

根据排序过程中借助的主要操作,我们将内排序分为四类: 插入排序类 直接插入排序 希尔排序 选择排序类 简单选择排序 堆排序 交换排序类 冒泡排序 快速排序 归并排序类 归并排序 从算法的简单性来看,我们将7种算法分为两类: 简单算法:冒泡排序.简单选择排序.直接插入排序 改进算法:希尔排序.堆排序.归并排序.快速排序 对7中算法的各种指标进行对比: 平均情况看:显然最后三种算法要胜过希尔算法,并远远超过前3种简单算法. 最好情况看:反而冒泡和直接插入排序要更胜一筹,也就是说,如果待排序序列总是基

[数据结构与算法]排序算法(Python)

1.直接插入排序 给定一个数组后,从第二个元素开始,如果比第一个小,就跟他交换位置,否则不动:第三个元素如果比第二个小,把第三个跟第二个交换位置,在把第二个与第一个比较:..... def insert_sort(arr): length = len(arr) for i in range(1,length): if arr[i] < arr[i-1]: for j in range(i-1,-1,-1): if arr[j+1] < arr[j]: arr[j+1],arr[j] = arr