单元测试二进制搜索

时间:2013-07-03 11:55:59

标签: python

我在实现二进制搜索的修改版本时遇到一些困难(它只需要检查子列表中是否有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等)。

3 个答案:

答案 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