Algorithm 对ArrayBuffer的二进制搜索
因此,我有一个ArrayBuffer[Signal],其中每个信号都有一个时间戳(数组按这个时间戳排序)。我想进行二进制搜索并返回一定范围内信号的Seq[Signal]。现在它是用线性搜索完成的,基本上是因为我来自Java,我是Scala的新手。哪种方法最好 代码如下:Algorithm 对ArrayBuffer的二进制搜索,algorithm,scala,performance,data-structures,binary-search-tree,Algorithm,Scala,Performance,Data Structures,Binary Search Tree,因此,我有一个ArrayBuffer[Signal],其中每个信号都有一个时间戳(数组按这个时间戳排序)。我想进行二进制搜索并返回一定范围内信号的Seq[Signal]。现在它是用线性搜索完成的,基本上是因为我来自Java,我是Scala的新手。哪种方法最好 代码如下: private def getSignalsFromCache(mapId: String, mac: String, startTime: Long, endTime: Long): Seq[Signal] = { val
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
}
private def getSignalsFromCache(mapId:String,mac:String,startTime:Long,endTime:Long):Seq[Signal]={
val signals=getCache(VehicleWithMap(mapId,mac))
val结果:ArrayBuffer[信号]=新的ArrayBuffer[信号]()
if(signals.isEmpty){
返回信号
}
变量startIndex:Int=0
if(startTime>signals.head.timestamp){
while(startIndex结束时间){
完成=正确
}
否则{
结果+=信号(当前索引)
}
当前索引+=1
}
后果
}
您可以使用搜索进行二进制搜索
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)
您可以使用&.这样,就可以保存所有的易变性和迭代 注意:这仍然是线性的,但它在Scala中更具功能和更常见
private def getSignalsFromCache(mapId: String, mac: String, startTime: Long, endTime: Long): Seq[Signal] =
getCache(VehicleWithMap(mapId, mac)
.dropWhile(_.timestamp < startTime)
.takeWhile(_.timestamp <= endTime)
}
private def getSignalsFromCache(mapId:String,mac:String,startTime:Long,endTime:Long):Seq[Signal]=
getCache(VehicleWithMap(mapId,mac)
.dropWhile(u.timestamp .takeWhile(u.timestamp我不知道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)
}
private def getSignalsFromCache(mapId:String,mac:String,startTime:Long,endTime:Long):Seq[Signal]={
val signals=getCache(VehicleWithMap(mapId,mac))
变量startIndex:Int=0
var endIndex:Int=signals.size
而(startIndex)据我所知,数组缓冲区是按升序排序的,对吗?@LuisMiguelMejíaSuárez是的,这似乎很简单。用startIndex+=1
替换为startIndex+=0.5长度的一半,方向正确()
。这只是记账的问题。排序。按(\u.timestamp)如果有多个具有下限时间戳的信号,此方法可能会错过其中一些信号,因为search.search不一定会返回第一个匹配结果。您可以通过对顺序进行调整来解决这一问题,但此时只编写二进制搜索就变得更简单、更清晰了。@Guillem你能告诉我发生的错误吗?也许你需要导入排序吗?@Matt是的,你可以用线性搜索来跟踪二进制搜索的边缘,但是如果有很多重复项,这会影响运行时间。我同意如果考虑重复项,实现二进制搜索会更好。@BrianMcCutchon问题是我非常擅长Scala.Signal中的er是一个case类,因此当我执行signals.search(startTime)(Ordering.by(u.timestamp))时,IDE无法解析,因为没有定义特殊的顺序。我的case类是这样的:case类Signal(ap:AccessPoint,timestamp:Long,rssi:Double,mac:String=”“).我如何定义排序以及如何使用它调用方法搜索?谢谢Brian,你太棒了!