只是想确保你不一个家庭作业问题。我这样做只是为了一些乐趣,可能是博客。
我根据此wiki page实施了“快速排序”的“就地”版本。
这是我写的代码:
# solution 2
def swap(arr, left, right):
try:
tmp = arr[left]
arr[left] = arr[right]
arr[right] = tmp
except IndexError:
print "!IndexError: left, right", left, right
raise
def partition(arr, left, right, pindex):
pivot = arr[pindex]
swap(arr, right, pindex)
npindex = left
for i in range(left, right+1): # +1 so the last item is included
if arr[i] < pivot:
swap(arr, i, npindex)
npindex += 1
swap(arr, npindex, right)
return npindex
def qs(arr):
qs2(arr, 0, len(arr)-1)
return arr
def qs2(arr, left, right):
if left < right:
# midpoint = (right - left) / 2
midpoint = left # this works.
nindex = partition(arr, left, right, midpoint)
qs2(arr, left, nindex-1)
qs2(arr, nindex+1, right)
def test():
test = [23, 45, 12, 1, 3, -9, 67, 122, 8, 2, 0]
res = qs(list(test))
print "start\t", test
print "end\t", res
if __name__ == "__main__":
test()
我不明白的是,根据维基百科的说法,只要它位于维基百科中,枢轴的选择(函数 qs2 中的变量中点)可以是随机的界限。
但是,如果我只取中点(即(左+右)/ 2),则快速排序不起作用。使用左值,它可以正常工作。
在理解算法时我是否遗漏了什么?
编辑:我刚刚意识到stackoverflow中有一个'quicksort'标记。如果之前已经问过这个问题,我的道歉并请告诉我。我将结束这个问题。与此同时,我将通过快速标记
来解决这些问题答案 0 :(得分:2)
你有midpoint = (right - left) / 2
。我认为你的意思是(right + left) / 2
,否则你的中点超出给定范围。
答案 1 :(得分:2)
由于存在整数溢出,选择枢轴元素也很复杂。如果被排序的子数组的边界索引足够大,则中间索引(左+右)/ 2的朴素表达式将导致溢出并提供无效的数据透视索引。这可以通过使用例如左+(右 - 左)/ 2来索引中间元素来克服,代价是更复杂的算术。在选择枢轴元素的其他一些方法中也会出现类似的问题。
应该是(left + right) / 2
,而不是(right - left) / 2
。维基百科解释说,使用left + (right - left) / 2
是为了避免整数溢出。