快速排序算法讲解

原理介绍

本次讲解结合 《清华大学PYthon》的部分PPT演示以及本人的神仙手绘,如果本博客看不懂的,欢迎留言提问,也建议大家去哔哩哔哩搜索《python清华大学讲解》结合该视频观看。
快速排序的原理非常简单:
1.首先选取一个初始值(我们一般默认为第一个数字就是初始参考值),设置两个初始指针(最左和最右侧)
选取好后,将初始值拿出,并且从数组的最右一侧开始遍历查找比初始值小的数值,找到后,则将该数填补到初始值的位置(位置替换),右侧指针位置停留在该数上
2.接下来,从左侧(第二位)开始向左遍历查找比初始值更大的数值(注意是更大!!!),找到数值后,则将该数放到之前那个数的位置上,左侧指针停留在该数的位置上。
3.继续从右侧开始,查找更小数值。(构成一个循环递归)
4.当左右两侧的指针重合时,则递归结束,初始值的位置已经安置好了,此时初始值的左侧的数都比初始值小,初始值右侧的数都比初始值大。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5.完成一次初始值归位(记下该位为mid)后,接下来分别在初始值的左侧和初始值的右侧开始新的递归:
(1)只看左侧部分:取左侧首元素(第一个元素),和左侧末元素(mid-1)。重复上述的过程。
(2)只看右侧部分:取右侧的首元素(mid+1),和末位元素,重复上述过程。

代码演示

本次代码演示为python实现
Python演示的过程中会附带详细讲解:

def partition(li,left,right) #分别传入数组,以及左右侧的位置信息
   tmp = li[left] #保留最左侧的元素
   while left<right: #左侧指针的位置和右侧指针的位置不相逢
     while li[left]<=li[right]:
       right-=1 
   

上述代码有一个很致命的逻辑错误!
我们看看内循环,内循环只要左侧数值小于或者等于右侧数值指针就可以继续移动,但问题是,当指针移动到最左侧时(因为初始值是数组序列中最小的数),等号成立(此时的值和初始值相同),如图所示:
在这里插入图片描述
看见了吗?bug就在这儿!
但是可能有人会问,我的外层循环条件是 left<right ,当right=left 的时候,循环不是会跳出来吗?是的,但是内层循环的进行仅仅受到内层循环条件的影响,外层的循环条件不会干扰内层循环的进行,现在我们来看一个测试代码:

a=0
while a<10:
    while a<80:
        print(a)
        a+=1

输出结果如下:
在这里插入图片描述

可以看出,虽然外层循环限制a<10,但是丝毫不影响内存循环的进行.
好,那么我们的bug讲解完了,现在我们再接着讲解一下如何去修改这个代码。
为了防止出现这个bug,因此我们需要在内层循环之中添加 left<right作为条件:

def partition(li,left,right) #分别传入数组,以及左右侧的位置信息
   tmp = li[left] #保留最左侧的元素(保留初始值)
   while left<right : #左侧指针的位置和右侧指针的位置不相逢
     while li[left]<=li[right] and left < right:
       right-=1  #指针向左移动
     li[left]=li[right]  #把右边找到的值赋值到左边空位
     while li[left]<=li[right] and left < right:#对左边开始也同样操作
       left+=1  #如果没找到对应的数值,那么指针继续右移
     li[right]= li[left] #找到之后,填补之前right的空位(替换值)
   li[left]=tmp #此时第一轮分类完毕(分大小),初始值归位结束。也可以写成li[right]=tmp,因为此时的left和right相等。
         

现在我们开始用个例子验证一下:

def partition(li,left,right):
    tmp=li[left] #保留初始值
    while left<right:
        while left<right and li[right]>=tmp:
            right-=1
        li[left]=li[right]
        print("第一次")
        print(li)
        while left<right and li[left]<=tmp:
            left+=1
        li[right]=li[left]
        print("第二次")
        print(li)
    li[left]=tmp

li=[20,21,98,19,97,8,4]
partition(li,0,len(li)-1)
print("最终结果")
print(li)

结果如下:(变化过程)
第一次(表示右查找)
第二次(表示左查找)
在这里插入图片描述

最终,20的左边都比20小,20的右边都比20大!
第一轮分类结束了,同样的道理,对于归位后的左侧和右侧也可以重复上述的过程,那么这就是递归。
最终代码如下:
(递归概念不熟悉的小伙伴建议回去复习复习)
总体的排序过程简述图大概如下:
在这里插入图片描述

def partition(li,left,right):
    tmp=li[left] #保留初始值
    while left<right:
        while left<right and li[right]>=tmp:
            right-=1
        li[left]=li[right]
        print("第一次")
        print(li)
        while left<right and li[left]<=tmp:
            left+=1
        li[right]=li[left]
        print("第二次")
        print(li)
    li[left]=tmp
    mid = left #保留当前的位置
    return mid #返回当前的位置信息,便于下一轮排序
def sort(li,left,right):
    if left <right: #指针位置不重合继续递归,指针位置重合时则归为完成结束递归,原理与 partition函数相似
      mid = partition(li,left,right) #返回mid值,接下来进行左侧和右侧的排序
      sort(li,left,mid-1)  #对归位值的左侧排序,进入递归
      sort(li,mid+1,right) #对归位值的右侧排序,进入递归
li=[20,21,98,19,97,8,4]
sort(li,0,len(li)-1)
print("最总结果为:")
print(li)

``
过程如下:
```python
在这里插入代码片

每两次为一轮:

第一次
[4, 21, 98, 19, 97, 8, 4]
第二次
[4, 21, 98, 19, 97, 8, 21]
第一次
[4, 8, 98, 19, 97, 8, 21]
第二次
[4, 8, 98, 19, 97, 98, 21]
第一次
[4, 8, 19, 19, 97, 98, 21]
第二次
[4, 8, 19, 19, 97, 98, 21]
第一次
[4, 8, 19, 20, 97, 98, 21]
第二次
[4, 8, 19, 20, 97, 98, 21]
第一次
[4, 8, 19, 20, 97, 98, 21]
第二次
[4, 8, 19, 20, 97, 98, 21]
第一次
[4, 8, 19, 20, 21, 98, 21]
第二次
[4, 8, 19, 20, 21, 98, 98]
第一次
[4, 8, 19, 20, 21, 98, 98]
第二次
[4, 8, 19, 20, 21, 98, 98]
最总结果为:
[4, 8, 19, 20, 21, 97, 98]


快速排序算法的实现就讲解到这里啦!
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值