让我们首先实现三个数的中值,所以是一个独立的函数。我们可以对三个元素的列表进行排序,然后返回第二个元素,如:
def median_of_three(a, b, c):
return sorted([a, b, c])[1]
现在是一个范围
low .. high
用
low
包括,和
high
不包括在内),我们应该确定哪些元素是我们应该构建三个中值的元素:
第一个要素:
L[low]
,
最后一个元素
L[high-1]
和
中间元素(如果有两个这样的元素,则取第一个)
L[(low+high-1)//2]
.
所以现在我们只需要将分区函数修补到:
def Partition(L, low, high, ascending = True):
print('Quicksort, Parameter L:')
print(L)
result = 0
pivot = median_of_three(L[low], L[(low+high-1)//2], L[high-1])
i = low + 1
for j in range(low + 1, high, 1):
result += 1
if (ascending and L[j] < pivot) or (not ascending and L[j] > pivot):
L[i], L[j] = L[j], L[i]
i += 1
L[low], L[i-1] = L[i-1], L[low]
return i - 1, result
编辑
:确定三个元素的中值。
三个元素的中间值是位于其他两个值中间的元素。所以以防万一
a <= b <= c
然后
b
是中间值。
所以我们需要确定元素的顺序,这样我们就可以确定中间的元素。像:
def median_of_three(a, b, c):
if a <= b and b <= c:
return b
if c <= b and b <= a:
return b
if a <= c and c <= b:
return c
if b <= c and c <= a:
return c
return a
现在我们定义了三和四的中值
if
病例。
编辑2
:这个还是有问题的。执行轴操作后,交换元素
L[i-1]
具有
低[低]
在原始代码中(轴的位置)。但这当然不再起作用:因为轴心现在可以位于三维中的任何一个。因此我们需要
median_of_three(..)
更聪明:它不仅应该返回pivot元素,还应该返回pivot的位置:
def median_of_three(L, low, high):
mid = (low+high-1)//2
a = L[low]
b = L[mid]
c = L[high-1]
if a <= b <= c:
return b, mid
if c <= b <= a:
return b, mid
if a <= c <= b:
return c, high-1
if b <= c <= a:
return c, high-1
return a, low
现在我们可以用以下方法解决这个问题:
def Partition(L, low, high, ascending = True):
print('Quicksort, Parameter L:')
print(L)
result = 0
pivot, pidx = median_of_three(L, low, high)
i = low + (low == pidx)
for j in range(low, high, 1):
if j == pidx:
continue
result += 1
if (ascending and L[j] < pivot) or (not ascending and L[j] > pivot):
L[i], L[j] = L[j], L[i]
i += 1 + (i+1 == pidx)
L[pidx], L[i-1] = L[i-1], L[pidx]
return i - 1, result
编辑3
:清理干净。
尽管上面的方法似乎有效,但它相当复杂:我们需要
i
和
j
“跳过”轴的位置。
如果我们首先将轴心移到子列表的前面(这样
低的
指数):
def Partition(L, low, high, ascending = True):
print('Quicksort, Parameter L:')
print(L)
result = 0
pivot, pidx = median_of_three(L, low, high)
L[low], L[pidx] = L[pidx], L[low]
i = low + 1
for j in range(low+1, high, 1):
result += 1
if (ascending and L[j] < pivot) or (not ascending and L[j] > pivot):
L[i], L[j] = L[j], L[i]
i += 1
L[low], L[i-1] = L[i-1], L[low]
return i - 1, result