我试图实现我刚刚在课堂上学到的rselect算法。但是,似乎无法弄清楚我在实施中出错了。这是我的代码。 * 编辑* :我尝试使用David提供的答案中提供的信息,但我的代码仍然很奇怪。这是修改后的代码:
def rselect(seq,length,i):# i is the i'th order statistic.
if len(seq)<=1:return seq
lo,pi,hi,loc_pi= random_partition(seq
if loc_pi==i:return pi
if loc_pi>i:return rselect(lo,loc_pi-1,i)
elif loc_pi<i:return rselect(hi,length-loc_pi,i-loc_pi)#
from random import choice
def random_partition(seq):
pi =choice(seq)
#print 'pi',pi
loc_pi=seq.index(pi)
print 'Location',loc_pi
lo=[x for x in seq if x<=pi]
hi=[x for x in seq if x>pi]
return lo,pi,hi,len(lo)+1 #--A
def test_rselect(seq,i):
print 'Sequence',seq
l=len(seq)
print 'Statistic', rselect(seq,l,i)
然而,输出在不同的时间是不同的,有时甚至是正确的!我对算法和python都是一个菜鸟,对于我出错的地方的任何帮助都会非常感激。 编辑:我每次运行代码时都会得到第i个订单统计数据的不同值,这是我的问题 例如,下面的代码的每次运行都给出了
Revised Output:
/py-scripts$ python quicksort.py
Sequence [54, -1, 1000, 565, 64, 2, 5]
Statistic Location 1
-1
@ubuntu:~/py-scripts$ python quicksort.py
Sequence [54, -1, 1000, 565, 64, 2, 5]
Statistic Location 5
Location 1
Location 0
-1
预期输出:我期待在这里找到第i个订单统计数据。
因此
test_rselect([54,-1,1000,565,64,2,5],2)
应始终将5
作为统计信息返回。
任何有关此实施方式出错的帮助都会有所帮助..谢谢!
编辑2 :从尝试分析算法开始,我认为错误在于我如何在标记为A的行中返回枢轴位置(loc_pi)。考虑以下因素上述程序的事件序列。
test_rselect( [ 55, 900, -1,10, 545, 250], 3) // call to input array
calls rselect ([ 55, 900, -1,10, 545, 250],6,3)
1st call to random_partition:
pi=545 and loc_pi=4
lo=[55,-1,10,250,545]
hi=[900]
return to rselect function (lo,545,hi,6)
here loc_pi>i: so rselect(lo,5,3)// and discard the hi part
2nd recursive call to rselect:
2nd recursive call to random_partition:
call random_partition on (lo) // as 'hi' is discarded
pi=55 loc_pi=0
lo=[-1,10,55]
hi=[250,545]
return to rselect(lo,55,hi,4)
here loc_pi>i: rselect(lo,3,3)// The pivot element is lost already as it is in 'hi' here!!
有关如何处理返回枢轴元素位置的任何帮助,以获得正确的o / p将会有所帮助。设置赏金,以获得明确解释我在哪里做错了以及我如何纠正错误的答案(因为我很期待学习,所以很受欢迎。) 。期待很好的答案!
答案 0 :(得分:2)
您算法的问题在于您对loc_pi
的确定。例如,考虑1000是pi
中选择的第一个loc_pi=seq.index(pi)
的情况。在这种情况下,loc_pi
将等于2,因为1000在序列的索引2处,并且函数将返回1000,我们知道这绝对不是订单统计2。
因此,我们知道我们无法根据随机选择的loc_pi
的索引来确定pi
。毕竟,该列表是任意顺序 - 它的位置没有任何意义。您实际想要获得loc_pi
值的是该子列表中低于您选择的pi 的元素数量。幸运的是,这很容易获得!只需更改一行:
return lo,pi,hi,loc_pi
到
return lo,pi,hi,len(lo) + 1
你会发现它的表现正确且一致!
dynamic-oit-vapornet-c-913:test dgrtwo$ python test21.py
Sequence [54, -1, 1000, 565, 64, 2, 5]
Statistic pi 565
Location 3
pi 5
Location 5
pi -1
Location 0
pi 2
Location 0
2
dynamic-oit-vapornet-c-913:test dgrtwo$ python test21.py
Sequence [54, -1, 1000, 565, 64, 2, 5]
Statistic pi -1
Location 1
pi 54
Location 0
pi 5
Location 2
pi 2
Location 0
2
ETA:请注意,如果输入序列中存在联系,则写入的算法将 not 始终有效。试试几个例子,你就会明白我的意思。有一些简单的方法可以解决它,我相信你可以搞清楚。
答案 1 :(得分:1)
如果你改变:
return lo,pi,hi,len(lo)+1
为:
return lo,pi,hi,len(lo)
并添加一个右括号)
,以便更正语法错误,如下所示:
lo,pi,hi,loc_pi= random_partition(seq)
对于没有重复输入的序列,它将可靠地工作:
for i in xrange(1,8):
print rselect([54,-1,1000,565,64,2,5],7,i),
#Output:
-1 2 5 54 64 565 [1000]
这是预期的输出。
我想我的主要建议是尝试按照style guidlines!进行编码。您的代码一目了然非常棘手!
参数length
是多余的,因此可以完全删除。而且有时最后一个条目将作为单个值列表返回,所以我已经改变了(虽然如果你把它传递给一个空列表它会知道摔倒,可能不是什么大问题)。以下是稍微更易读的格式的代码,其中包含允许重复输入的更正:
from random import choice, shuffle
def rselect(seq, i):
lo, hi, pi, loc_pi = random_partition(seq)
if loc_pi == i or (min(lo) == max(lo) and not hi):
return pi
elif loc_pi > i:
return rselect(lo, i)
elif loc_pi < i:
return rselect(hi, i - loc_pi)
def random_partition(seq):
pi = choice(seq)
lo = [x for x in seq if x <= pi]
hi = [x for x in seq if x > pi]
return lo, hi, pi, len(lo)
#this is a nice way to test it:
cat = range(1,21)
for i in xrange(1,21):
shuffle(cat)
print rselect(cat,i),
#Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
答案 2 :(得分:1)
我认为没有任何主要错误(你如何返回枢轴或其他方面),这只是很多一个(甚至两个)混乱,加上我认为你的意思是与我在rselect的第一行,而不是1。
这是我对它的看法,尽可能少的改变:
def rselect(seq,length,i):# i is the i'th order statistic.
if len(seq)<=i:return seq
lo,pi,hi,loc_pi= random_partition(seq)
if loc_pi==i:return pi
if loc_pi>i:return rselect(lo,loc_pi,i)
elif loc_pi<i:return rselect(hi,length-(loc_pi+1),i-(loc_pi+1))
from random import choice
def random_partition(seq):
pi =choice(seq)
lo=[x for x in seq if x<=pi]
hi=[x for x in seq if x>pi]
return lo,pi,hi,len(lo)-1
编辑:如果存在重复元素,这是一个应该有效的版本。现在,我不得不改变一些,所以我拿出了一些令我困惑的东西,以便让自己更容易。
def rselect(seq,i):# i is the i'th order statistic.
if len(seq)<=i:return seq
lo,pi,hi= random_partition(seq)
if i < len(lo):return rselect(lo,i)
if i < len(seq)-len(hi): return pi
return rselect(hi,i-(len(seq)-len(hi)))
from random import choice
def random_partition(seq):
pi =choice(seq)
lo=[x for x in seq if x<pi]
hi=[x for x in seq if x>pi]
return lo,pi,hi
def test_rselect(seq,i):
print 'Sequence',seq
stat=rselect(seq,i)
print 'Statistic', stat