我在实现二进制搜索的修改版本时遇到一些困难(它只需要检查子列表中是否有1,然后继续搜索直到它返回索引)。
目前我提出的代码是:
def binary_search(inList):
low = 0
high = len(inList) -1
while low <= high:
mid = (low+high)//2
upper = inList[mid:high]
lower = inList[low:mid-1]
if any(lower):
inList = lower
high = mid-1
elif any(upper):
inList = upper
low = mid
else:
return mid
assert low < high
return -1
它似乎适用于循环的几次迭代,但随后它返回空列表,并失败。我用以下输入测试了该函数:
l = [0 for x in range(256)]
l[123] = 1
我还注意到,当列表被抽取时,一些垃圾箱会丢失。
我将如何创建一个测试套件,它将捕获这些问题并让我将此算法扩展到其他输入集(例如,两半中的1,彼此相邻的两个1等)。
答案 0 :(得分:2)
您可以使用unittest
构建一个简单的测试套件,可以测试不同输入的结果,对于这个例子应该非常简单。
这应该让你开始 - 尝试运行这个脚本(在修改导入以导入你的二进制搜索模块之后),谷歌python unittest
应该给你很多关于如何扩展它的想法。
import unittest
from <your module> import binary_search
class TestBinarySearchForOne(unittest.TestCase):
def test_small_range(self):
self.assertEquals(1, binary_search(range(0, 2))
def test_not_found(self):
self.assertEquals(-1, binary_search([0, 4, 9, 190])
if __name__ == '__main__':
unittest.main()
答案 1 :(得分:2)
男人你要问三个问题,但没有什么。
要创建一个测试套装,只需编写一些好的示例并断言它们有效,例如:
from binary_search import binary_search
# Test a basic case
inlist = [0] * 256
inlist[123] = 1
assert binary_search(inlist) == 123
# Test a case with odd len
inlist = [0] * 99
inlist[20] = 1
assert binary_search(inlist, 20)
# Test the case with no 1s
inlist = [0] * 256
assert binary_search(inlist) == -1
# It's good to test corner cases just in case
inlist = [0] * 256
inlist[0] = 1
assert binary_search(inlist) == 0
inlist = [0] * 256
inlist[255] = 1
assert binary_search(inlist) == 255
您可能需要考虑使用诸如nose或unittest模块之类的东西来帮助您组织测试,但无论如何,每次更改代码时都要运行测试以确保它正常工作。如果您为代码添加新功能,例如允许在列表中搜索多个1,则需要为该行为添加测试。
你可能已经知道这一点,但是我想提一下,这是一个非常差的算法,用于在列表中查找1。问题是any
是一个O(N)操作,因此在循环的每次迭代中,您都要进行N / 2或N次操作。循环运行log(N)次。有一点数学涉及,但你可以很容易地证明这是一个O(N * log(N))算法,而只需使用inlist.index(1)
(或一个基本的for循环),你可以在N个操作中找到1
然而,为了帮助你学习我继续并修复你的算法这是一个工作版本,它通过了上述测试:)
def binary_search(inList):
low = 0
high = len(inList)
while low < high:
mid = (low + high) // 2
upper = inList[mid:high]
lower = inList[low:mid]
if any(lower):
high = mid
elif any(upper):
low = mid + 1
else:
# Neither side has a 1
return -1
assert low == high
return mid
您的版本的主要问题是您正在修改低/高并同时修改inlist。因为低/高是入库的索引,当您修改入库时,它们不再指向正确的位置。
答案 2 :(得分:1)
我完全不明白你要做什么;您只需要在“经典”算法中更改两行,如Wikipedia中所示:
def binary_search(inList):
low = 0
high = len(inList) - 1
while low <= high:
mid = low + (high - low) // 2
if any(inList[low:mid - 1]): # <- this one
high = mid - 1
elif any(inList[mid + 1:high]): # <- this one
low = mid + 1
else:
return mid
return -1
这对我有用:
>>> binary_search(l)
123