对索引集合进行二进制搜索(已排序的索引序列)

时间:2012-01-26 18:32:50

标签: scala indexing binary-search

我有某种类型A索引集合(必须编入索引):

var coll: IndexedSeq[A]

我希望coll根据某些Ordering[A]排序,但我经常在其中添加/删除项目。这样做的明显机制是:

def binarySearch[A : Ordering](a: IndexedSeq[A], elem: A): Int
def add(a: A) {
  val idx = binarySearch(coll, a)
  coll = (coll take idx) :+ a +: (coll drop idx)
}

但是标准库中没有binarySearch(奇怪的是,看到有scala.util.Sorting.quickSort)并且没有我能找到的数据类型,它既被索引又被排序(我猜这是效率低下的结构。)

3 个答案:

答案 0 :(得分:3)

我认为sliceTreeSet的效率相当高(并且你可以将它用于单元素范围),但你是对的 - 奇怪的是没有索引排序的数据结构。它足够有效;如果跟踪孩子的数量,大多数任何排序的树都可以这样使用。我认为这只是一种疏忽而已。但

如果用一个只允许引用相等的标记包装它们,你总是可以使用一个重复元素集,并且你可以确保它们是有序的:

class Tag[A](val value: A)(implicit ord: Ordering[A]) extends Ordered[Tag[A]] {
  def compare(ta: Tag[A]) = {
    val c = ord.compare(value,ta.value)
    if (c != 0) c
    else if (this eq ta) 0
    else System.identityHashCode(this) compare System.identityHashCode(ta)
  }
  override def toString = value.toString+"'"
  override def hashCode = value.hashCode
  override def equals(a: Any) = a.asInstanceOf[AnyRef] eq this
}

scala> collection.immutable.TreeSet[Tag[Int]]() ++ List(1,2,3,2,1).map(i => new Tag(i))
res1: scala.collection.immutable.TreeSet[Tag[Int]] = TreeSet(1', 1', 2', 2', 3')

scala> res1.slice(2,3).head
res2: Tag[Int] = 2'

然而,这确实为相对简单的任务增加了很多开销。

答案 1 :(得分:2)

http://www.scala-lang.org/api/2.11.4/index.html#scala.collection.Searching $$ SearchImpl

  

在特定元素的排序序列中的间隔内搜索。如果序列是IndexedSeq,则使用二进制搜索。否则,使用线性搜索。

答案 2 :(得分:0)

def getPerson(userList: ArrayList[Person], person: Person): Integer = {
var low = 0;
var high = userList.size - 1

while (low <= high) {
  var mid = low + (high - low) / 2
  var midValue = userList.get(mid)
  if (person.firstName < midValue.firstName) {
    high = mid - 1;
  } else if (person.firstName > midValue.firstName) {
    low = mid + 1;
  } else {
    return mid
  }
}
return -1

}