4

我目前正在努力在 Scala 中实现我自己的Trie(出于学习/爱好目的),并且我正在尝试保持它的通用性(以便它可以存储任何可迭代的内容,而不仅仅是字符串)。我的班级签名看起来像

class Trie[Item <% Iterable[Part], Part](items: Item*) extends Set[Item]

我已经实现了包含、+= 和 -=(它扩展了 Set 的可变版本),但是我在使用迭代器时遇到了一些问题。我目前的方法让我挠头寻找一个优雅的实现。我有一种方法可以遍历所有的 TrieNode,并且只释放那些被标记为“有效结尾”的节点。从那里我计划按照父链接获取各个部分。(例如,树中的“hello”将存储为标记为结尾的“o”节点,父节点为“l”->“l”->“e”->“h”)

现在我的问题。由于我试图保持通用性,我无法从其“部件”中重建“项目”。所以我向 SO 的人们提出的问题是,处理这个问题的最优雅的方式是什么?我应该在构造函数参数中添加重建函数吗?应该Item有不同的界限以强制功能的存在吗?还是完全是别的东西?

4

1 回答 1

1

Item 和 Part 之间存在隐含的关系。至少,您需要将 Item 分解为 Part 对象,而要重构,您需要做相反的事情。

因此"hello": String,您需要有f("hello")return('h': Char, "ello": String)并且需要反函数g('h', "ello")return "hello"

因此,只要遵循一些规则,具有两个这样的功能的任何两种类型都可以。我认为规则很容易直觉。它或多或少是如何使用递归分解列表headtail使用重建它的::

您可以使用上下文绑定来为常用类型提供这些功能。

(编辑)

实际上我不能真正使用上下文绑定,因为有两个类型参数,但这是我的想法:

trait R[Item, Part] {
  def decompose(item: Item): (Part, Item)
  def recompose(item: Item, part: Part): Item
  def empty: Item
}

class NotATrie[Item, Part](item: Item)(implicit rel: R[Item, Part]) {
  val brokenUp = {
    def f(i: Item, acc: List[Part] = Nil): List[Part] = {
      if (i == rel.empty) acc
      else {
        val (head, tail) = rel.decompose(i)
        f(tail, head :: acc)
      }
    }
    f(item)
  }

  def rebuilt =  (rel.empty /: brokenUp)( (acc, el) => rel.recompose(acc, el) )
}

然后我们提供一些隐式对象:

implicit object string2R extends R[String, Char] {
  def decompose(item: String): (Char, String) = (item.head, item.tail)
  def recompose(item: String, part: Char): String = part + item
  def empty: String = ""
}

implicit object string2RAlt extends R[String, Int] {
  def decompose(item: String): (Int, String) = {
    val cp = item.codePointAt(0)
    val index = Character.charCount(cp)
    (cp, item.substring(index))
  }
  def recompose(item: String, part: Int): String = 
    new String(Character.toChars(part)) + item
  def empty: String = ""
}

val nat1 = new NotATrie[String, Char]("hello")
nat1.brokenUp  // List(o, l, l, e, h)
nat1.rebuilt   // hello

val nat2 = new NotATrie[String, Int]("hello\ud834\udd1e")
nat2.brokenUp // List(119070, 111, 108, 108, 101, 104)
nat2.rebuilt  // hello
于 2011-07-16T05:48:29.753 回答