二进制搜索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)
另一答案
你可以使用dropWhile
和takeWhile
。
这样,您可以保存所有可变性和迭代。
注意:这仍然是线性的,但它在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的主要内容,如果未能解决你的问题,请参考以下文章