[英]In-place QuickSort in Python
我必须用我选择的语言为作业实现 QuickSort 算法,我选择了 Python。
在讲座中,我们被告知 QuickSort 是内存高效的,因为它就地工作; 即,它没有用于递归的输入数组部分的额外副本。
考虑到这一点,我尝试在 Python 中实现 QuickSort 算法,但不久之后意识到为了编写一段优雅的代码,我必须在递归时将数组的一部分传递给函数本身。 由于每次执行此操作时 Python 都会创建新列表,因此我尝试使用 Python3(因为它支持 nonlocal 关键字)。 以下是我注释的代码。
def quicksort2(array):
# Create a local copy of array.
arr = array
def sort(start, end):
# Base case condition
if not start < end:
return
# Make it known to the inner function that we will work on arr
# from the outer definition
nonlocal arr
i = start + 1
j = start + 1
# Choosing the pivot as the first element of the working part
# part of arr
pivot = arr[start]
# Start partitioning
while j <= end:
if arr[j] < pivot:
temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
i += 1
j += 1
temp = arr[start]
arr[start] = arr[i - 1]
arr[i - 1] = temp
# End partitioning
# Finally recurse on both partitions
sort(start + 0, i - 2)
sort(i, end)
sort(0, len(array) - 1)
现在,我不确定我是否做得很好,还是我遗漏了什么。 我写了一个更 Pythonic 的 QuickSort 版本,但这肯定不能就地工作,因为它不断返回输入数组的一部分并将它们连接起来。
我的问题是,这是在 Python 中的做法吗? 我已经搜索了 Google 和 SO,但还没有找到真正的 QuickSort 就地实现,所以我认为最好问一下。
当然不是最好的方法,加上这个著名的算法会有几十个完美的实现..这是我的,很容易理解
def sub_partition(array, start, end, idx_pivot):
'returns the position where the pivot winds up'
if not (start <= idx_pivot <= end):
raise ValueError('idx pivot must be between start and end')
array[start], array[idx_pivot] = array[idx_pivot], array[start]
pivot = array[start]
i = start + 1
j = start + 1
while j <= end:
if array[j] <= pivot:
array[j], array[i] = array[i], array[j]
i += 1
j += 1
array[start], array[i - 1] = array[i - 1], array[start]
return i - 1
def quicksort(array, start=0, end=None):
if end is None:
end = len(array) - 1
if end - start < 1:
return
idx_pivot = random.randint(start, end)
i = sub_partition(array, start, end, idx_pivot)
#print array, i, idx_pivot
quicksort(array, start, i - 1)
quicksort(array, i + 1, end)
好的,首先是分区子程序的单独函数。 它需要数组、感兴趣的起点和终点以及枢轴的索引。 这个功能应该清楚
然后快速排序在整个数组上第一次调用分区子程序; 然后调用 recursevely 本身将所有内容排序到主元和之后的所有内容。
问你是否有不明白的地方
我最近开始学习python,以下是我使用python实现quicksort的尝试。 希望它有帮助。 欢迎反馈:)
#!/usr/bin/python
Array = [ 3,7,2,8,1,6,8,9,6,9]
def partition(a, left, right):
pivot = left + (right - left)/2
a[left],a[pivot] = a[pivot], a[left] # swap
pivot = left
left += 1
while right >= left :
while left <= right and a[left] <= a[pivot] :
left += 1
while left <= right and a[right] > a[pivot] :
right -= 1
if left <= right:
a[left] , a[right] = a[right], a[left] # swap
left += 1
right -= 1
else:
break
a[pivot], a[right] = a[right] , a[pivot]
return right
def quicksort(array , left,right):
if left >= right:
return
if right - left == 1:
if array[right] < array[left]:
array[right], array[left] = array[left] , array[right]
return
pivot = partition(array, left, right)
quicksort(array, left, pivot -1)
quicksort(array, pivot+1,right)
def main():
quicksort(Array, 0 , len(Array) -1)
print Array
main()
这是另一个实现:
def quicksort(alist):
if len(alist) <= 1:
return alist
return part(alist,0,len(alist)-1)
def part(alist,start,end):
pivot = alist[end]
border = start
if start < end:
for i in range(start,end+1):
if alist[i] <= pivot:
alist[border], alist[i] = alist[i], alist[border]
if i != end:
border += 1
part(alist,start,border-1)
part(alist,border+1,end)
return alist
这是我想出的。 该算法是就地的,看起来不错并且是递归的。
# `a` is the subarray we're working on
# `p` is the start point in the subarray we're working on
# `r` is the index of the last element of the subarray we're working on
def part(a,p,r):
k=a[r] #pivot
j,q=p,p
if p<r: # if the length of the subarray is greater than 0
for i in range(p,r+1):
if a[i]<=k:
t=a[q]
a[q]=a[j]
a[j]=t
if i!=r:
q+=1
j+=1
else:
j+=1
part(a,p,q-1) # sort the subarray to the left of the pivot
part(a,q+1,r) # sort the subarray to the right of the pivot
return a
def quicksort(a):
if len(a)>1:
return part(a,0,len(a)-1)
else:
return a
说明:枢轴始终是给定数组中的最后一个元素。 在我的方法中,我跟踪小于和大于枢轴的数字之间的“边界”。 Border 是“更大”组中第一个数字的索引。 在每次迭代结束时,我们将“边界”下的数字与枢轴编号交换。
和代码:
def qs(ar, start, end):
if (end-start < 1):
return
if (end-start == 1):
if(ar[start] > ar[end]):
tmp = ar[start]
ar[start] = ar[end]
ar[end] = tmp
return
pivot = ar[end - 1]
border_index = start
i = start
while(i <= end - 1):
if (ar[i] < pivot):
if i > border_index:
tmp = ar[i]
ar[i] = ar[border_index]
ar[border_index] = tmp
border_index += 1
i+=1
ar[end-1] = ar[border_index]
ar[border_index] = pivot
qs(ar, start, border_index)
qs(ar, border_index + 1, end)
qs(ar, 0, n)
def quicksort(arr):
lesser = []
equal = []
greater = []
if len(arr)>1:
pivot = arr[len(arr)-1]
start = 0
while start<len(arr):
if arr[start] > pivot:
greater.append(arr.pop(start))
elif arr[start] < pivot:
lesser.append(arr.pop(start))
else:
start = start + 1
return (quicksort(lesser) + arr + quicksort(greater))
else:
return (arr)
print(quicksort([2,333,-22,0,54, 22, 37, 0.3, -2, 22]))
以枢轴为最右侧元素的就地实现
def partition(array, begin, end):
pivot = end
while begin < pivot:
if array[begin] > array[pivot]:
if begin != pivot - 1:
array[pivot], array[pivot - 1] = array[pivot - 1], array[pivot]
array[begin], array[pivot] = array[pivot], array[begin]
pivot-=1
else:
begin+=1
return pivot
def quicksort(array, begin=0, end=None):
if end is None:
end = len(array) - 1
if begin < end:
partition_index = partition(array, begin, end)
quicksort(array, begin, (partition_index - 1))
quicksort(array, (partition_index + 1), end)
说明 - 分区
1.以支点为“结束”——最右边的元素
2.按排序顺序将枢轴带到正确的位置。
3.比较开始时的元素与枢轴元素
当所有元素都被检查时循环中断,由 [begin] 重叠 [pivot] 指示。 开始==支点
如果 elem[begin] > elem[pivot]
元素大于 elem[pivot]。 它在错误的地方。 它必须在枢轴之后出现
交换元素 [pivot] 和 [pivot-1] if (pivot-1) != begin
交换元素 [pivot] 和 [begin]
现在枢轴处的元素位于 [pivot-1] 位置或当前 [begin] 位置
无论哪种方式,枢轴都向左移动了一个位置。 所以将枢轴减 1
别的
元素在开始是 <= 枢轴和枢轴的左侧。
所以它处于可以接受的位置
增量开始检查下一个元素
说明 - 快速排序
1.选择一个枢轴,将其放置在数组中的正确位置并使用“partition()”方法获取其索引。
2.使用begin、end和partition_index将数组划分为pivot的左侧和右侧
3.在pivot的左右侧数组上调用quicksort
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.