我试图找到一个元素的等级,定义为k,在未排序的列表中,等级将是列表中第k个最低值。
E.G。 给出一个清单: [5,4,1,10,8,3,2]
其中k为1,值为1 其中k为3,值为3 其中k为6,值为8 其中k为7,值为10
我必须使用下面提供的修改后的快速分配功能。
def partition(a_list, first, last):
pivot = a_list[last]
i = first - 1
for j in range(first, last):
if a_list[j] <= pivot:
i += 1
a_list[i], a_list[j] = a_list[j], a_list[i]
a_list[i + 1], a_list[last] = a_list[last], a_list[i + 1]
return i + 1
我正在寻找一个预期运行时间为O(n)的函数,我试图通过调用partition来递归浏览列表,然后决定是通过右半边还是左边一半,但我实际上没有得到预期的结果。这是我的选择方法。
def selection(a_list, first, last, k):
intReturn = partition(a_list, first, last)
print(a_list)
print(intReturn)
if intReturn == k:
return a_list[intReturn - 1]
else:
if intReturn < k:
return selection(a_list, first + intReturn, last, k) #- (first + intReturn))
elif intReturn > k:
return a_list[k]
#return selection(a_list, first, last - intReturn, k)
应该按如下方式调用选择函数:
print(selection([5,4,1,10,8,3,2], 0, 6, 1))
print(selection([5,4,1,10,8,3,2], 0, 6, 3))
print(selection([5,4,1,10,8,3,2], 0, 6, 6))
print(selection([5,4,1,10,8,3,2], 0, 6, 7))
print(selection([46, 50, 16, 88, 79, 77, 17, 2, 43, 13, 86, 12, 68, 33, 81, \
74, 19, 52, 98, 70, 61, 71, 93, 5, 55], 0, 24, 19))
所以,是的,我如何在预期的运行时间O(n)递归地找到给定某个等级的元素而不必对整个列表进行排序?虽然仅限于这种特殊的分区方式。
答案 0 :(得分:1)
Python烹饪书中至少有两个已经完成的例子here和here。
这是我的版本:
import random
def select(data, n):
"Find the nth rank ordered element (the least value has rank 0)."
data = list(data)
if not 0 <= n < len(data):
raise ValueError('not enough elements for the given rank')
while True:
pivot = random.choice(data)
pcount = 0
under, over = [], []
uappend, oappend = under.append, over.append
for elem in data:
if elem < pivot:
uappend(elem)
elif elem > pivot:
oappend(elem)
else:
pcount += 1
if n < len(under):
data = under
elif n < len(under) + pcount:
return pivot
else:
data = over
n -= len(under) + pcount
根据您的要求,这是相同代码的递归版本:
def select(data, n):
"Find the nth rank ordered element (the least value has rank 0)."
if not 0 <= n < len(data):
raise ValueError('not enough elements for the given rank')
pivot = random.choice(data)
pcount = 0
under, over = [], []
uappend, oappend = under.append, over.append
for elem in data:
if elem < pivot:
uappend(elem)
elif elem > pivot:
oappend(elem)
else:
pcount += 1
if n < len(under):
return select(under, n)
elif n < len(under) + pcount:
return pivot
else:
return select(over, n - len(under) - pcount)
答案 1 :(得分:0)
试试这个?一个可能有帮助的观察是分区函数返回pivot元素的索引(从零开始)。
def selection(a_list, first, last, k):
assert (k - 1 >= first)
assert (k - 1 <= last)
intReturn = partition(a_list, first, last)
if intReturn + 1 == k:
return a_list[intReturn]
if intReturn + 1 < k:
return selection(a_list, intReturn + 1, last, k)
if intReturn + 1 > k:
return selection(a_list, first, intReturn - 1, k)