二进制搜索实现中的Swift可选参数

时间:2018-09-11 00:23:15

标签: swift

我想在Swift中编写一个很好的Binary Search实现,以下似乎是一种在所有情况下都能克服传递上下限的技巧。

func binarySearch(arr: [Int], target: Int, _ lowerBound: Int? = 0, _ upperBound: Int? = 0) -> Int? {
    var ub = upperBound
    if (ub == 0 ) { ub = arr.count
}

深入说明:我已经编写了以下形式的一组测试: XCTAssertEqual(binarySearch(arr: [1,2,3,4], target: 5), nil)

而且我不想在第一个实例中将上下限传递给二进制搜索。

我的函数头看起来像:

func binarySearch(arr: [Int], target: Int, _ lowerBound: Int? = 0, _ upperBound: Int? = 0) -> Int? {

在每次二进制搜索的递归调用中,下界要么为零,要么为传递的参数,这很有意义。但是上限没有。

现在我想写一些类似的

func binarySearch(arr: [Int], target: Int, _ lowerBound: Int? = 0, _ upperBound: arr.count) -> Int? {

但是显然这是不可能的。

我什至想添加以下内容(但显然不能,因为upperBound是一个let常量):

if (upperBound == 0 ) {upperBound = arr.count}

我想使用:

func binarySearch(arr: [Int], target: Int, _ lowerBound: Int? = 0, _ var upperBound: Int? = 0) -> Int? {

但是看起来这不再是迅速的功能。

我离开时不得不按如下方式使用一个额外的变量,因为这太乱了!

func binarySearch(arr: [Int], target: Int, _ lowerBound: Int? = 0, _ upperBound: Int? = 0) -> Int? {
    var ub = upperBound
    if (ub == 0 ) {ub = arr.count}

2 个答案:

答案 0 :(得分:1)

我将使上限参数成为可选参数(如您所愿),但将默认参数设置为nil。然后,将您的本地ub值创建为:

let ub = upperbound ?? arr.count

下限应该是非可选的,默认值为0

func binarySearch(arr: [Int], target: Int, _ lowerBound: Int = 0, _ upperBound: Int? = nil) -> Int? {
    let ub = upperBound ?? arr.count

答案 1 :(得分:1)

这是常见的情况。递归函数的签名可能需要比其入口点更多的参数。解决此问题的最佳方法是使用嵌套函数。

func binarySearch(_ array: [Int], for target: Int) -> Int? {
    func binarySearch(_ array: [Int], for: Int, lowerBound: Int, upperBound: Int) -> Int? {
        // your implementation here
    }

    return binarySearch(array, for: target, lowerBound: 0, upperBound: array.count)
}

有关更多Swifty代码,建议您尝试使用以下方法进行转换:

  • 扩展,而不是将参数有效地用于“自我”的自由函数
  • 一个范围而不是2个独立的Int
  • 具有最少参数的公共入口点和私有递归函数将为递归提供所有必需的参数。

这是一个入门示例:

extension RandomAccessCollection where Self.IndexDistance == Int {
    public func binarySearch(for target: Element) -> Int? {
        return binarySearch(for: target, inRange: 0 ..< self.count)
    }

    private func binarySearch(for target: Element, inRange range: CountableRange<Int>) -> Int? {
        return nil // Your implementation here
    }
}