排序算法之快速排序举例详解-python实现3版代码及改进过程

快速排序思想步骤:

1.找到一个基准值key

2.设置2个元素下标i=0和j=len-1

3.从后往前找到比key小的数num[j],从前往后找到比key大的数num[i](这里有个先后顺序)

4.交换这两个数:num[i],num[j]

5.继续重复该过程,直到i==j,完成一趟排序(循环结束条件)

6.以num[j]为界限,左右2边分别进行快速排序

图片来源于百度:

 

总结:

确定一个数字的准确位置,再递归它分出来的两个数组,直到递归规模缩小为1停止,最终整个数组会趋于有序。

注意:

i和j先后顺序不重要,但是每次都必须按照第一次的顺序来。如果第一次是i先走,后面的子分组快速排序也得i先走。

举例

num=[1,3,4,2,6,5]

1.找到基准值(首尾都行),key=1

2.num[i]=1,num[j]=5

3.j--找到比1小的第一个数

4.此时j=i(满足j<=i找不到),第一趟快速排序结束,数字1为有序。

此时顺序为:[1,3,4,2,6,5]

5.数字1左边的分组数据<=1左边分组已经有序,右边的分组继续进行快速排序

6.选择基准值key=3,num[i]=3,num[j]=5

7.j--找到比3小的第一个数,num[j]=2

8.i++找到比3大的第一个数,num[i]=4

9.交换num[i]和num[j]

此时顺序为:[1,3,2,4,6,5]

10.j--找比3小的第一个数,num[i]=2,此时j==i

11.交换key和num[j],发现3为分界线的左边 只有1个数字:2。(子分组,1为有序了)所以只需要对3右边进行快速排序。

此时顺序为:[1,2,3,4,6,5]

12.找基准值4,num[i]=4,num[j]=5

13.j--找到比4小的第一个数,找不到,此时i=j,num[i]==num[j]==key,4为有序

此时顺序为:[1,2,3,4,6,5]

14.找到基准值6,num[i]=6,num[j]=5

15.j--找到比6小的第一个数,5

16.i++找到比6大的第一个数,找不到,此时i=j,num[i]==num[j]==5

17.交换key和num[j]

此时顺序为:[1,2,3,4,5,6]

第4步和第17步体现了i和j顺序的作用。

由于我这里是j先走,所以,num[j]往前走到i==j还是没找到比key小的数的话,说明key是有序,不用交换。---对应第4步

当j--找到了比key小的第一个数(i不等于j时)之后,i++,直到i==j都没找到比key大的数,此时交换key和num[j]。----对应第17步

代码实现:

第一版代码(存在重复元素会陷入死循环)

1.设置基准值变量key,游标i,j。i是起始索引,j是结束索引

2.通过一个partition函数去完成num[i],num[j]的交换,函数返回索引mid,mid为划分子分组的界限

3.快速排序函数:参数为列表,开始索引,结束索引(用来传给partition函数获取mid索引)

4.以mid索引为界限,对左右两边子分组分别递归调用快速排序函数。

def partition(num,i,j):
    key=num[i]
    while i<j:
        while i<j and num[j]>key:
            j=j-1
        while i<j and num[i]<key:
            i=i+1
        num[i],num[j]=num[j],num[i]
    return j

def quick_sort(num,i,j):
    if i<j:
        mid = partition(num, i, j)
        quick_sort(num,i,mid-1)
        quick_sort(num, mid + 1, j)
# num=[1,3,4,2,6,5]
num = [5, 7, 4, 6, 3, 1, 2, 9, 8]
i=0
j=len(num)-1
quick_sort(num,i,j)
print(num)


partition函数:

1.当i小于j的时候,判断num[j]>key就一直执行j=j-1,直到找到一个num[j]<=key

2.再判断i<j并且num[i]>key,一直执行i=i+1,直到找到一个num[i]>=key

3.交换num[i]和num[j]的值

当列表内没有重复元素时,初版代码完美实现。

第二版代码(重复元素测试通过)

但是当列表中存在重复元素,会跳过partition中两个内循环,所以并不会有i和j的更改。

直接在外面的循环中一直交换2个元素,就陷入了死循环。于是,我在第一版代码的基础上又做了一些改进得到第二版代码。

思路沿用第一版,具体实现区别在于partition函数。

partition函数:

1.设置基准值key=num[i](我设置的左边的值为基准值)

2.循环比较num[j]和key的大小,如果num[j]>=key,执行j=j-1。当num[j]<key的时候,停止循环,然后把num[j]赋值给num[i](此时比key大的数放到左边去了)

3.循环比较num[i]和key的大小,如果num[i]<=key,执行i=i+1。当num[i]>key的时候,停止循环,把num[i]赋值给num[j](此时比key小的数放到右边了)

4.把key的值赋值给num[i],相当于key为中间值,第一轮结束,小的数已分到了左边,大的数分到了右边。

def partition(num,i,j):
    key=num[i]
    while i<j:
        while i<j and num[j]>=key:
            j=j-1;
        num[i]=num[j]
        while i<j and num[i]<=key:
            i=i+1
        num[j]=num[i]
    num[i]=key
    return i

def quick_sort(num,i,j):
    if i<j:
        mid = partition(num, i, j)
        quick_sort(num,i,mid-1)
        quick_sort(num, mid + 1, j)
# num=[1,3,4,2,6,5]
num=[1,0,2,2,1,0]
# num = [5, 7, 4, 6, 3, 1, 2, 9, 8]
i=0
j=len(num)-1
quick_sort(num,i,j)
print(num)


在没有重复元素的时候,2-3步相当于第一版代码的外循环里面的交换。

当有重复元素的时候,也会交换,但是不会陷入上一版代码的死循环了。

上一版代码由于没有重复元素,所以内循环里,>=和<=的效果都一样。这版代码是有重复元素的,所以得加上=。

因为如果j=j-1找到小于key的元素,就要进行交换。如果是找到相等元素,可以不进行交换。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值