由于额外的变量、糟糕的变量名称(j 通常用作索引,而不是布尔标志)、break 的使用、嵌套条件和side effect,此代码难以推理。这也是低效的,因为它需要在最坏的情况下访问列表中的每个元素,并且无法充分利用列表的排序特性。但是,它似乎有效。
您的第一个误解可能是print(i) 正在打印下一个最大元素的索引,而不是元素本身。在您对 occur1([2, 20, 30], 3)) 的示例调用中,1 是 20 在数组中的位置。
其次,一旦找到的元素被打印出来,函数在退出循环后返回None,print尽职尽责地打印None。希望这可以解释您的输出 - 您可以使用 return a[i] 代替 break 来解决您的直接问题并满足您的期望。
话虽如此,Python 有一个内置模块:bisect。这是一个例子:
from bisect import bisect_right
a = [1, 2, 5, 6, 8, 9, 15]
index_of_next_largest = bisect_right(a, 6)
print(a[index_of_next_largest]) # => 8
如果大于k 的下一个数字超出范围,您可以try/except 或使用条件来报告您认为合适的失败。该函数利用了列表使用binary search algorithm 排序的事实,这将每一步的搜索空间减半。时间复杂度为 O(log(n)),非常快。
如果您确实希望坚持使用类似于您的解决方案的线性算法,您可以将您的逻辑简化为:
def occur1(a, num_to_find):
for n in a:
if n > num_to_find:
return n
# test it...
a = [2, 5, 10]
for i in range(11):
print(i, " -> ", occur1(a, i))
输出:
0 -> 2
1 -> 2
2 -> 5
3 -> 5
4 -> 5
5 -> 10
6 -> 10
7 -> 10
8 -> 10
9 -> 10
10 -> None
或者,如果你想要下一个最大数的索引:
def occur1(a, num_to_find):
for i, n in enumerate(a):
if n > num_to_find:
return i
但我想强调的是,无论从哪方面来说,二分搜索都远优于线性搜索。对于十亿个元素的列表,在线性版本将进行十亿次比较的最坏情况下,二分搜索将进行大约 20 次比较。不使用它的唯一原因是如果不能保证列表是预先排序的,这里不是这种情况。
为了更具体,您可以使用这个程序(但在实践中使用内置模块):
import random
def bisect_right(a, target, lo=0, hi=None, cmps=0):
if hi is None:
hi = len(a)
mid = (hi - lo) // 2 + lo
cmps += 1
if lo <= hi and mid < len(a):
if a[mid] < target:
return bisect_right(a, target, mid + 1, hi, cmps)
elif a[mid] > target:
return bisect_right(a, target, lo, mid - 1, cmps)
else:
return cmps, mid + 1
return cmps, mid + 1
def linear_search(a, target, cmps=0):
for i, n in enumerate(a):
cmps += 1
if n > target:
return cmps, i
return cmps, i
if __name__ == "__main__":
random.seed(42)
trials = 10**3
list_size = 10**4
binary_search_cmps = 0
linear_search_cmps = 0
for n in range(trials):
test_list = sorted([random.randint(0, list_size) for _ in range(list_size)])
test_target = random.randint(0, list_size)
res = bisect_right(test_list, test_target)[0]
binary_search_cmps += res
linear_search_cmps += linear_search(test_list, test_target)[0]
binary_search_avg = binary_search_cmps / trials
linear_search_avg = linear_search_cmps / trials
s = "%s search made %d comparisons across \n%d searches on random lists of %d elements\n(found the element in an average of %d comparisons\nper search)\n"
print(s % ("binary", binary_search_cmps, trials, list_size, binary_search_avg))
print(s % ("linear", linear_search_cmps, trials, list_size, linear_search_avg))
输出:
binary search made 12820 comparisons across
1000 searches on random lists of 10000 elements
(found the element in an average of 12 comparisons
per search)
linear search made 5013525 comparisons across
1000 searches on random lists of 10000 elements
(found the element in an average of 5013 comparisons
per search)
添加的元素越多,线性搜索的情况就越糟糕。