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

发布于 2024-12-29 07:49:45 字数 512 浏览 0 评论 0原文

我有一个A类型的索引集合(必须已索引):

var coll: IndexedSeq[A]

我希望根据某些排序保持coll排序[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)并且我找不到既可以索引又可以排序的数据类型(我猜这是一个低效的结构)。

I have an indexed collection (it must be indexed) of some type A:

var coll: IndexedSeq[A]

I wish to keep coll sorted according to some Ordering[A] but I am frequently adding/removing items to/from it. The obvious mechanism to do this is something like:

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)
}

But there is neither a binarySearch in the standard library (odd, seeing as there is scala.util.Sorting.quickSort) and there is no datatype I can find that is both indexed and sorted (I guess that this is an inefficient structure).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一片旧的回忆 2025-01-05 07:49:45

我认为 TreeSet 上的 slice 相当有效(并且您可以将它与单元素范围一起使用),但您是对的 - 没有索引很奇怪排序的数据结构。而且效率足够高;如果跟踪子级的数量,则大多数排序树都可以以这种方式使用。我认为这只是一个疏忽,它的缺失。

如果您使用仅允许引用相等的标记包装重复元素,则始终可以对它们使用集合,并且可以确保它们是有序的:

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'

但是,对于相对简单的任务,这确实会增加大量开销。

I think slice on TreeSet is reasonably efficient (and you can use it with a one-element range), but you're right--it's strange that there is no indexed sorted data structure. And it's efficient enough; most any sorted tree can be used that way if the number of children are tracked. I think it's just an oversight that it's missing.

You can always use a set for repeated elements if you wrap them with a tag that only allows reference equality, and you can make sure they're ordered:

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'

This does add a lot of overhead for a comparatively simple task, however.

依 靠 2025-01-05 07:49:45

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

在排序序列的某个区间内搜索特定元素。如果序列是 IndexedSeq,则使用二分搜索。否则,将使用线性搜索。

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

Search within an interval in the sorted sequence for a specific element. If the sequence is an IndexedSeq, a binary search is used. Otherwise, a linear search is used.

鹿童谣 2025-01-05 07:49:45
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

}

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

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文