快速排序
快速排序的核心在于中间值的选取,以及数组的划分
算法的思路是:
1.将数组切割成两半,保证左边的数值小于中点值p值,右半边数组的数值大于中点値p
0.假设中点値p为第一个数,
1.使用双指针:i位于指针头部(从第1个开始,因为0已经是p了),j位于指针尾部
如果i指向的数值小于p,则i++往右移动,否则停下来(while)
如果j指向的数值大于p,则j++向做移动,否则停下来 (while)
如果两个指针都停下来了,就交换i,j处的数值
如果i>=j,则跳出循环,因为此时已经确保了j处的指针的数值肯定是小于p的了,(i处的数值可能会大于p,这种一般是i>j了)
同时交换j和0处的数值
2.分别对左半边和右半边数组重复以上步骤
这里以leetcode 912 题为例,这题可用快速排序实现,但是在选取中间值的时候需要随机一个值,不然很难过官方的测试用例。
这里我实现了for和while两个版本
def partition_for(nums,l,r):
p_idx = random.randint(l,r)
nums[p_idx],nums[r] = nums[r],nums[p_idx] #此时中点値已经挪到最右了
i = l - 1 #i的目的是记录i所在的值比中点値大
for j in range(l,r):
if nums[j] < nums[r]: #j所在的值比中点値小
i += 1 #小于才自增,大于不自增,目的是为了让i处的值大于中点値
nums[i],nums[j] = nums[j],nums[i]
#跳出循环后我们能保证 i的右边都已经是大于中点値的了(因为j肯定是比i先走的,j经历过的地方肯定都已经是没有小于中点値的了),但是i当前的值是小于中点値的(因为刚交换过了)
i += 1
nums[i],nums[r] = nums[r],nums[i]
return i
def partition_while(nums,start,end):
if start == end:
return end
p_idx = random.randint(start,end)
nums[start],nums[p_idx] = nums[p_idx],nums[start]
p = nums[start]
left = start
right = end
while left < right:
while left <= end and nums[left] <= p:
left += 1
while right >= start and nums[right] > p:
right -= 1
if left >= right:
break
nums[left],nums[right] = nums[right],nums[left]
#left停下来的时候肯定会保证left指向的数会大于p
#right停下来的时候肯定会保证right指向的数会小于p
#所以left遇到right停下来的时候,right当前的位置肯定是小于p的,但是right右边的值会大于p
nums[right],nums[start] = nums[start],nums[right]
return right
class Solution(object):
def quickSort(self, nums, l, r):
if r - l <= 0:
return
mid = partition_while(nums, l, r)
self.quickSort(nums, l, mid - 1)
self.quickSort(nums, mid + 1, r)
def sortArray(self, nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
self.quickSort(nums,0,len(nums) - 1)
return nums

浙公网安备 33010602011771号