排序算法-快速排序

一、快速排序

快速排序也属于交换排序,通过元素之间的比较和交换位置来达到排序的目的。

冒泡排序在每一轮中只把1个元素冒泡到数列的一端。而快速排序则在每一轮挑选一个基准元素 ,并让其他比它大的元素移动到数列一边 ,比它小的元素移动到数列的另一边,从而把数列拆解成两个部分。

这种思路就叫作分治法。

在分治法的思想下,原数列在每一轮都被拆分成两部分,每一部分在下一轮又分别被拆分成两部分,直到不可再分为止。 每一轮的比较和交换,需要把数组中的全部元素都遍历一遍,时间复杂度是O(n)。这样的遍历一共需要多少轮呢﹖假如元素个数是n,那么平均情况下需要logn轮,因此快速排序算法总体的平均时间复杂度是O ( nlogn)。

基准元素,英文pivot,在分治过程中,以基准元素为中心,把其他元素移动到它的左右两边。

1、双边循环法。

2、单边循环法。

1、双边循环法

首先,选定基准元素pivot,并且设置两个指针left和right,指向数列的最左和最右两个元素。

第1次循环,从right指针开始,让指针所指向的元素和基准元素做比较。如果right>=pivot,则指针向左移动(-1);如果right<pivot,则right指针停止移动(stop),切换到left指针。

在当前数列中,1<4,所以right直接停止移动,换到left指针,进行下一步行动。轮到left指针行动,让指针所指向的元素和基准元素做比较。如果left<=pivot,则指针向右移动(+1);如果left>pivot,则left指针停止移动(stop)。

由于left开始指向的是基准元素,判断肯定相等,所以left右移1位。

由于7>4,left指针在元素7的位置停下。这时,让left指针和right指针所指向的元素进行交换。

python 复制代码
def partition(start,end,ll):
    '''
     比较交换过程
    :param start: 开始索引
    :param end: 结束索引
    :param ll:  数列
    :return:   左边索引
    '''
    #取第一个元素为基准元素,也可以随机
    pirot=ll[start]
    #左边元素索引
    left=start
    #右边元素索引
    right=end
    #循环
    while left!=right:
        #控制right指针比较,并左移
        while left<right and ll[right]>=pirot:
            right -=1
        # 控制left指针比较,并右移
        while left<right and ll[left]<=pirot:
            left+=1
        #交换left指针和right指针的元素
        if left<right:
            #交换
            ll[left],ll[right]=ll[right],ll[left]
    #pirot与left,right指针重合
    ll[start]=ll[left]
    ll[left]=pirot
    return left

def quickSort(start,end,ll):
    #递归结束
    if start>=end:
        return
    #获取基准元素位置
    pirot=partition(start,end,ll)
    #根据基准元素,分成两部分递归排序
    quickSort(start,pirot-1,ll)
    quickSort(pirot+1,end,ll)

if __name__ == '__main__':
     ll=[4,7,6,5,3,2,8,1]
     print('排序前:')
     print(ll)
     #调用方法排序
     quickSort(0,len(ll)-1,ll)
     print('排序后:')
     print(ll)

2、单边循环法

只从数组的一边对元素进行遍历和交换。

开始和双边循环法相似,首先选定基准元素pivot。同时,设置一个mark指针指向数列起始位置 ,这个mark指针代表小于基准元素的区域边界。接下来,从基准元素的下一个位置开始遍历数组。

如果遍历到的元素**>**基准元素,就继续往后遍历。

如果遍历到的元素**<**基准元素,则需要做两件事:

第一,把mark指针右移1位,因为小于pivot的区域边界增大了1;

第二,让最新遍历到的元素和mark指针所在位置的元素交换位置,因为最新遍历的元素归属于小于pivot的区域。

首先遍历到元素7,7>4,所以继续遍历。

遍历到的元素是3,3<4,所以mark指针右移1位。

随后,让元素3和mark指针所在位置的元素交换,因为元素3归属于小于pivot的区域。

python 复制代码
def partitionSingle(start,end,ll):
    # 取第一个元素为基准元素,也可以随机
    pirot = ll[start]
    # 标记索引
    mark = start
    for i in range(start+1,end+1):
        #判断遍历的元素<基准元素
        if ll[i]<pirot:
            #右移1位
            mark+=1
            #交换
            p=ll[mark]
            ll[mark]=ll[i]
            ll[i]=p

    ll[start]=ll[mark]
    ll[mark]=pirot
    return mark


def quickSort(start,end,ll):
    #递归结束
    if start>=end:
        return
    #获取基准元素位置
    pirot=partitionSingle(start,end,ll)
    #根据基准元素,分成两部分递归排序
    quickSort(start,pirot-1,ll)
    quickSort(pirot+1,end,ll)

很明显,partitionSingle方法只要一个循环就OK,的确比双边循环法简单多了。

相关推荐
一只码代码的章鱼41 分钟前
粒子群算法 笔记 数学建模
笔记·算法·数学建模·逻辑回归
小小小小关同学41 分钟前
【JVM】垃圾收集器详解
java·jvm·算法
圆圆滚滚小企鹅。1 小时前
刷题笔记 贪心算法-1 贪心算法理论基础
笔记·算法·leetcode·贪心算法
Kacey Huang1 小时前
YOLOv1、YOLOv2、YOLOv3目标检测算法原理与实战第十三天|YOLOv3实战、安装Typora
人工智能·算法·yolo·目标检测·计算机视觉
eguid_11 小时前
JavaScript图像处理,常用图像边缘检测算法简单介绍说明
javascript·图像处理·算法·计算机视觉
带多刺的玫瑰2 小时前
Leecode刷题C语言之收集所有金币可获得的最大积分
算法·深度优先
LabVIEW开发2 小时前
PID控制的优势与LabVIEW应用
算法·labview
涅槃寂雨2 小时前
C语言小任务——寻找水仙花数
c语言·数据结构·算法
『往事』&白驹过隙;2 小时前
操作系统(Linux Kernel 0.11&Linux Kernel 0.12)解读整理——内核初始化(main & init)之缓冲区的管理
linux·c语言·数据结构·物联网·操作系统
就爱学编程2 小时前
从C语言看数据结构和算法:复杂度决定性能
c语言·数据结构·算法