我一直致力于在 Python 中实现常见的排序算法,在处理 selection sort 时,我遇到了一个问题,即查找子列表的最小值并将其与子列表的第一个值交换,从我的测试似乎是由于我在程序中使用 min()
的方式存在问题。
这是我的代码:
def selection_sort(li):
for i in range(0, len(li)):
a, b = i, li.index(min(li[i:]))
li[a], li[b] = li[b], li[a]
这适用于其中包含零个重复元素的列表:
>>> selection_sort([9,8,7,6,5,4,3,2,1])
[1, 2, 3, 4, 5, 6, 7, 8, 9]
然而,当列表中有重复元素时,它完全失败。
>>> selection_sort([9,8,8,7,6,6,5,5,5,4,2,1,1])
[8, 8, 7, 6, 6, 5, 5, 5, 4, 2, 9, 1, 1]
我试图通过检查 min()
在我的代码的第 3 行所做的事情来解决这个问题,并发现 min()
按预期返回了子列表中最小元素的索引值,但是索引是更大列表中的元素而不是子列表的元素,我希望这个实验有助于更清楚地说明:
>>> a = [1,2,1,1,2]
>>> min(a)
1 # expected
>>> a.index(min(a))
0 # also expected
>>> a.index(min(a[1:]))
0 # should be 1?
我不确定是什么导致了这种行为;可以将 li[i:]
复制到临时变量 b
中,然后执行 b.index(min(b))
,但是将 li[i:]
复制到 b
为每个循环可能需要很多内存和选择排序是 in-place algorithm 所以我不确定这种方法是否理想。
答案 0 :(得分:1)
你没有完全正确地理解这个概念!
li.index(item) 将返回该项目在列表 li 中的第一次出现。 相反,您应该做的是,如果您在子列表中找到最小元素,则在子列表中搜索该元素,而不是在整个列表中搜索它。同样在切片列表中搜索时,您将获得关于子列表的索引。尽管您可以通过将开始步骤添加到返回的索引中来轻松解决该问题。
解决您的问题的一个小方法是:
def selection_sort(li):
for i in range(0, len(li)):
a, b = i, i + li[i:].index(min(li[i:]))
li[a], li[b] = li[b], li[a]
答案 1 :(得分:0)
一种方法是使用列表理解:
idxs = [i for i, val in enumerate(a) if val == min(a)]
或者更好的是,编写自己的代码,这样渐近地更快:
idxs = []
minval = None
for i, val in enumerate(a):
if minval is None or minval > val:
idxs = [i]
minval = val
elif minval == val:
idxs.append(i)
答案 2 :(得分:0)
当您编写 a.index(min(a[1:]))
时,您正在搜索 min
的 a[1:]
第一次出现,但您正在在原始列表中搜索</strong>。这就是您得到 0
的原因。
顺便说一下,你要找的函数一般叫argmin
。它不包含在纯 python 中,但 numpy
模块包含它。