array.count和array [0 ... <index]是否会减慢二进制搜索的速度?

道格拉斯·菲佛

今天我做了一份工作测试,并被要求搜索一个整数数组,这是一个问题:

本练习的目的是检查数组中数字的存在。

规格:

这些项是按升序排列的整数

阵列最多可包含一百万个项目

实现功能existInArray(_numbers:[Int],_ k:Int),以便如果k属于数字则返回true,否则函数应返回false

例:

let numbers = [-9, 14, 37, 102]
existsInArray(numbers, 102) // returns true
existsInArray(numbers, 36) //returns false

注意:尝试节省CPU周期

好吧,所以我给了我下面的代码,然后等待结果

func existsInArray(_ numbers: [Int], _ k: Int) -> Bool {
    if numbers.isEmpty {
        return false
    }
    let numbersHalfIndex: Int = (numbers.count/2)
    if k == numbers[numbersHalfIndex] {
        return true
    } else if k != numbers[0] && numbers.count == 1 {
        return false
    } else if k <= numbers[numbersHalfIndex] {
        let leftHalfNumbersArray = numbers[0 ..< numbersHalfIndex]
        return existsInArray(Array(leftHalfNumbersArray), k)
    } else if k > numbers[numbersHalfIndex] {
        let rightHalfNumbersArray = numbers[numbersHalfIndex ..< numbers.count]
        return existsInArray(Array(rightHalfNumbersArray), k)
    } else {
        return false
    }
}

原来,“该解决方案无法在合理的时间内处理一百万个项目”,现在我不知道自己做错了什么,因为二进制搜索的速度与f * ck一样快。

我唯一的猜测是,也许number.countnumbers [0 ... <numbersHalfIndex]numbers [numbersHalfIndex ... <number.count]会使一切变得比预期的慢。

我在绊倒吗?

编辑:如果有人好奇,我测试了我的代码和Martin R代码,以了解使用ArraySlice在时间方面的影响。我使用从0开始以升序排列的100.000.000 iten数组。这是我捕获时间的方式:

print("////////// MINE //////////")
var startTime = CFAbsoluteTimeGetCurrent()
print(existsInArray(numbers, 0))
var timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for mine: \(timeElapsed) s.")

print("////////// Martin R //////////")
counter = 0
startTime = CFAbsoluteTimeGetCurrent()
print(existsInArrayOptimal(numbers, 0))
timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
print("Time elapsed for Martin R: \(timeElapsed) s.")

结果如下:

////////// MINE ///////////

真正

我的时间:

1.2008800506591797秒

/////////// Martin R ///////////

真正

Martin R经过的时间:0.00012993812561035156 s。

快约1000倍!

马丁·R

访问number.count不是问题,因为这是数组的O(1)操作。切片numbers[0 ...< numbersHalfIndex]也不是问题。但是Array(leftHalfNumbersArray)从切片创建一个新数组,并复制所有元素。

有两种方法可以避免这种情况:

  • 更新数组索引(针对当前搜索范围的上下限),而不是创建沿递归传递的数组。
  • 递归递减数组切片切片与原始数组共享元素(只要它们没有突变)。

第二种方法的演示:

func existsInArray(_ numbers: ArraySlice<Int>, _ k: Int) -> Bool {
    if numbers.isEmpty {
        return false
    }
    let numbersHalfIndex = numbers.startIndex + numbers.count / 2
    if k == numbers[numbersHalfIndex] {
        return true
    } else if k < numbers[numbersHalfIndex] {
        return existsInArray(numbers[..<numbersHalfIndex], k)
    } else {
        return existsInArray(numbers[(numbersHalfIndex + 1)...], k)
    }
}

请注意,数组切片与原始数组共享索引,因此索引不必从零开始。numbers.startIndex就是用于索引计算的原因。

还有一个包装函数,它需要一个“真实的”数组参数:

func existsInArray(_ numbers: [Int], _ k: Int) -> Bool {
    return existsInArray(numbers[...], k)
}

正如@Leo建议的那样,您可以将其实现为一个收集方法,而不是实现两个单独的方法。集合索引不一定是整数,但是对于a而言RandomAccessCollection,索引计算保证为O(1)。您也可以将其概括为任意可比较元素的集合,而不是整数。

这是一个可能的实现:

extension RandomAccessCollection where Element: Comparable {
    /// Returns a Boolean value indicating whether the collection contains the
    /// given element. It is assumed that the collection elements are sorted
    /// in ascending (non-decreasing) order. 
    ///
    /// - Parameter element: The element to find in the collection.
    /// - Returns: `true` if the element was found in the collection; otherwise,
    ///   `false`.
    ///
    /// - Complexity: O(log(*n*)), where *n* is the size of the collection.
    func binarySearch(for element: Element) -> Bool {
        if isEmpty {
            return false
        }
        let midIndex = index(startIndex, offsetBy: count / 2)
        if element == self[midIndex] {
            return true
        } else if element < self[midIndex] {
            return self[..<midIndex].binarySearch(for: element)
        } else {
            return self[index(after: midIndex)...].binarySearch(for: element)
        }
    }
}

用法:

let numbers = [-9, 14, 37, 102]
print(numbers.binarySearch(for: 102)) // true
print(numbers.binarySearch(for: 36))  // false

另外,一种非递归方法可更新搜索范围的索引:

extension RandomAccessCollection where Element: Comparable {
    func binarySearch(for element: Element) -> Bool {
        var lo = startIndex
        var hi = endIndex

        while lo < hi {
            let mid = index(lo, offsetBy: distance(from: lo, to: hi) / 2)
            if element == self[mid] {
                return true
            } else if element < self[mid] {
                hi = mid
            } else {
                lo = index(after: mid)
            }
        }
        return false
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何检查输入是否为二进制格式(1和0)?

来自分类Dev

检查数字的二进制数是否等于0和1的否

来自分类Dev

反转二进制数组中的0和1

来自分类Dev

用二进制操作减少std :: array的constexpr

来自分类Dev

将由 0 和 1 组成的十六进制转换为等效的二进制

来自分类Dev

二进制搜索和二进制搜索树之间的区别?

来自分类Dev

二进制搜索和哈希表搜索

来自分类Dev

计算包含二进制数字“ 0”和“ 1”的行中的比率值

来自分类Dev

生成具有等于1和0的随机二进制向量

来自分类Dev

二进制作为int的1和0的列表

来自分类Dev

二进制数具有相同的0和1

来自分类Dev

二进制整数,以C为底的10到0和1之间的小数

来自分类Dev

我将如何逆转R中矩阵的二进制数字(0和1)?

来自分类Dev

如何以二进制格式打开文件。(1和0)

来自分类Dev

无法将1和0的字符串写入二进制文件,C ++

来自分类Dev

二进制数具有相同的0和1

来自分类Dev

计算包含二进制数字“ 0”和“ 1”的行中的比率值

来自分类Dev

在Numpy中提取二进制图像中0的行和列索引

来自分类Dev

C:将字符数组(包含'1'和'0')写入文件中的二进制文件

来自分类Dev

如何以1和0的字符串序列读取二进制文件?

来自分类Dev

如何在 fpdf 中显示 Yes 和 No 而不是二进制 1 & 0?

来自分类Dev

将 0 和 1 的字符串转换为它的二进制等效 python

来自分类Dev

在二进制搜索树中查找数字是否等于2个节点的和

来自分类Dev

JSON-String in PHP Array index 0

来自分类Dev

array [index] = 0;的目的是什么?

来自分类Dev

为什么&array!=&array [0]?

来自分类Dev

如何从相同的自定义编码二进制文件中定义二进制(1和0)序列以构成汇编语言?

来自分类Dev

如何将一些以 ASCII 0 和 1 表示的二进制文件转换为二进制文件?

来自分类Dev

php-in_array()和!in_array()检查0值

Related 相关文章

  1. 1

    如何检查输入是否为二进制格式(1和0)?

  2. 2

    检查数字的二进制数是否等于0和1的否

  3. 3

    反转二进制数组中的0和1

  4. 4

    用二进制操作减少std :: array的constexpr

  5. 5

    将由 0 和 1 组成的十六进制转换为等效的二进制

  6. 6

    二进制搜索和二进制搜索树之间的区别?

  7. 7

    二进制搜索和哈希表搜索

  8. 8

    计算包含二进制数字“ 0”和“ 1”的行中的比率值

  9. 9

    生成具有等于1和0的随机二进制向量

  10. 10

    二进制作为int的1和0的列表

  11. 11

    二进制数具有相同的0和1

  12. 12

    二进制整数,以C为底的10到0和1之间的小数

  13. 13

    我将如何逆转R中矩阵的二进制数字(0和1)?

  14. 14

    如何以二进制格式打开文件。(1和0)

  15. 15

    无法将1和0的字符串写入二进制文件,C ++

  16. 16

    二进制数具有相同的0和1

  17. 17

    计算包含二进制数字“ 0”和“ 1”的行中的比率值

  18. 18

    在Numpy中提取二进制图像中0的行和列索引

  19. 19

    C:将字符数组(包含'1'和'0')写入文件中的二进制文件

  20. 20

    如何以1和0的字符串序列读取二进制文件?

  21. 21

    如何在 fpdf 中显示 Yes 和 No 而不是二进制 1 & 0?

  22. 22

    将 0 和 1 的字符串转换为它的二进制等效 python

  23. 23

    在二进制搜索树中查找数字是否等于2个节点的和

  24. 24

    JSON-String in PHP Array index 0

  25. 25

    array [index] = 0;的目的是什么?

  26. 26

    为什么&array!=&array [0]?

  27. 27

    如何从相同的自定义编码二进制文件中定义二进制(1和0)序列以构成汇编语言?

  28. 28

    如何将一些以 ASCII 0 和 1 表示的二进制文件转换为二进制文件?

  29. 29

    php-in_array()和!in_array()检查0值

热门标签

归档