二进制搜索ArrayBuffer

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二进制搜索ArrayBuffer相关的知识,希望对你有一定的参考价值。

所以,我有一个ArrayBuffer [Signal],其中每个Signal都有一个时间戳(数组按此时间戳排序)。我想二进制搜索并返回一定范围内的信号的Seq [Signal]。现在它完成了线性搜索,主要是因为我来自Java,而且我是Scala的新手。这是最好的方法吗?

这是代码:

private def getSignalsFromCache(mapId: String, mac: String, startTime: Long, endTime: Long): Seq[Signal] = 

val signals = getCache(VehicleWithMap(mapId, mac))
val result: ArrayBuffer[Signal] = new ArrayBuffer[Signal]()

if (signals.isEmpty) 
  return signals


var startIndex: Int = 0
if (startTime > signals.head.timestamp) 

  while (startIndex < signals.size && signals(startIndex).timestamp < startTime) 
    startIndex += 1
  


var finished: Boolean = false
var currentIndex = startIndex
while (!finished && currentIndex < signals.size) 
  val timestamp = signals(currentIndex).timestamp
  if (timestamp > endTime) 
    finished = true
  
  else 
    result += signals(currentIndex)
  
  currentIndex += 1

result

答案

您可以使用“搜索”进行二分查找。

import scala.collection.Searching._

val signalWithLowerBoundTimestamp = ???
val signalWithUpperBoundTimestamp = ???
val lower = signals.search(signalWithLowerBoundTimestamp)(
    Ordering.by(_.timestamp)).insertionPoint
// If the upper bound is an exact match, add one
// to make sure it's included in the slice.
val upper = signals.search(signalWithUpperBoundTimestamp)(
    Ordering.by(_.timestamp)) match 
  case Found(i) => i + 1
  case InsertionPoint(i) => i

val result = signals.slice(lower, upper)
另一答案

你可以使用dropWhiletakeWhile。 这样,您可以保存所有可变性和迭代。

注意:这仍然是线性的,但它在Scala中更具功能性和更常见。

private def getSignalsFromCache(mapId: String, mac: String, startTime: Long, endTime: Long): Seq[Signal] =
  getCache(VehicleWithMap(mapId, mac)
    .dropWhile(_.timestamp < startTime)
    .takeWhile(_.timestamp <= endTime)

(确保先测试它,你可能需要根据条件进行一些测试)。

另一答案

我不知道scala,但这里是一个二进制搜索,你可以比较更多功能风格的答案。我不认为它有任何耻辱。请注意,对结束索引进行二进制搜索没有任何好处,因为您还是必须复制元素:

private def getSignalsFromCache(mapId: String, mac: String, startTime: Long, endTime: Long): Seq[Signal] = 

    val signals = getCache(VehicleWithMap(mapId, mac))

    var startIndex: Int = 0
    var endIndex: Int = signals.size

    while(startIndex<endIndex) 
        var testIndex: int = startIndex + (endIndex-startIndex)/2
        if (signals(testIndex).timestamp < startTime) 
            startIndex = testIndex + 1
         else 
            endIndex = testIndex
        
    

    while(endIndex < signals.size && signals(endIndex).timestamp <= endTime) 
        endIndex = endIndex + 1
    
    signals.slice(startIndex, endIndex)

请注意,我最后在timestamp == endTime中包含了信号,因为这就是你所做的......这使得界面有点奇怪。通常这样的方法会被写成用startTime <= timeStamp < endTime返回信号,所以也许你想考虑改变它。

以上是关于二进制搜索ArrayBuffer的主要内容,如果未能解决你的问题,请参考以下文章

使用二进制搜索的 Java 前缀搜索

搜索排序的链表时,二进制或顺序/线性搜索是不是更有效?

如何搜索二进制文件中的字符串

C ++中的线性搜索与二进制搜索实时性能

二进制/顺序搜索

如果已排序,则使用二进制搜索,否则使用线性搜索