快速排序
思路:取一个元素p(第一个元素),使元素p归位,列表被p分成两部分,左边都比p小,右边都比p大,进行递归完成排序。
时间复杂度:O(nlogn)
例:
排序前:5 7 4 6 3 1 2 9 8
p归位:2 1 4 3 5 6 7 9 8
目标:1 2 3 4 5 6 7 8 9
# 从小往大排
def partition(li, left ,right): # 实现元素归位
tmp = li[left]
while left < right:
while left < right and li[right] >= tmp: # 从右边找比tmp小的数
right -= 1 # 往左走一位
li[left] = li[right] # 把左边的值写到取出的空位上
while left < right and li[left] <= tmp: # 从左边找比tmp大的数
left += 1
li[right] = li[left] # 把左边的值写到取出的空位上
li[left] = tmp # 把tmp归位
return left
def quick_sort(li, left, right):
if left < right:
mid = partition(li, left, right)
quick_sort(li, left, mid-1)
quick_sort(li, mid+1, right)
li = [5, 7, 4, 6, 3, 7, 2, 9, 8]
quick_sort(li, 0, len(li)-1)
print(li)
问题说明:我在复习快排写代码的时候,在第二层while循环中忽视了left < right,这个条件,同时用的是条件li[left] <tmp,导致数组越界的错误,开始不理解为什么二层while循环要有这个条件,最后分析出来了原因。
在没有这个条件的情况下会发生两种错误:
-
数组越界:如果
right
指针在第一个while
循环中减少到小于left
指针,那么在尝试访问li[right]
时会发生数组越界错误。 -
无限循环:如果
left
和right
指针相遇(即left == right
),那么在没有left < right
条件的情况下,循环可能会变成无限循环,因为li[right] >= tmp
或li[left] < tmp
的条件可能永远为真。
在这个例子中发生的是在二层第二个while循环中的错误,如果二层第二个while循环条件没有left < right,同时用的是条件li[left] <tmp,则会导致数组越界:
开始数组:5 7 4 6 3 1 2 9 8
第一次归位:2 1 4 3 5 6 7 9 8
递归右半数组:
6 7 9 8
7 9 8
9 8 在这里li[right]=8<tmp=9 所以执行li[left] = li[right]=8,但是此时tmp=9,在二层第二个while循环中由于没有left < right这个条件,所以一直有li[left] < tmp成立,进而left会一直+1,当left加到9的时候就会出现访问li[9]的情况,也就是数组越界。
在上述代码中(条件为li[right] >= tmp)二层while循环中第一个while循环条件如果没有条件left < right,也会出现数组越界的情况,比如[5, 7, 4, 6, 3, 7, 2, 9, 8],会出现left和right指向同一个数,满足li[right] >= tmp,所以right会一直-1,最后会出现数组越界。
上述错误出现的原因是,我没有考虑到tmp与li[left]或li[right]相等的情况,同时忽略了left < right,上述分析可能有瑕疵,希望批评指正!