【问题标题】:newbie F# trie implementation gone wrong新手 F# trie 实现出错
【发布时间】:2011-02-15 20:37:29
【问题描述】:

我正在尝试在 F# 中实现 trie 数据结构。 我遇到了一些问题。 我无法调试单词插入功能。我在这个函数中的断点都没有达到崩溃,但我没有看到任何错误。 我也很怀疑我是否正确地实施了这件事。 无论如何这里是代码:

type TrieNode =
    | SubNodes of char * bool * TrieNode list
    | Nil
    member this.Char = match this with | Nil -> ' '
                                       | SubNodes(c,weh,subnodes) -> c
    member this.GetChild(c:char) = match this with  | Nil -> []
                                                    | SubNodes(c,weh,subnodes) ->[ (List.filter(fun (this:TrieNode) -> this.Char = c) subnodes).Head ]

    member this.AWordEndsHere = match this with | Nil -> false
                                                | SubNodes(c,weh,subnodes) -> weh
module TrieFunctions = 
    let rec insertWord (wordChars:char list) = function
        | Nil -> SubNodes(wordChars.Head, false, [])
        | SubNodes(c, weh, subnodes) as node ->
            let child = node.GetChild(wordChars.Head)
            if child = [] then 
                SubNodes(wordChars.Head,false,[insertWord wordChars.Tail node])
            else
                SubNodes(wordChars.Head,false,[insertWord wordChars.Tail child.Head])


type Trie(inner : TrieNode) =

    member this.InsertWord(wordChars:char list) = TrieFunctions.insertWord(wordChars)


  let trie = Trie(SubNodes(' ',false,List.empty)).InsertWord(['g';'i';'g';'i'])

所以我的问题是:
1. 如何获得对 insertWord 功能的调试访问权限?为什么我现在没有收到?为什么我没有看到错误?
2. 如何让函数 insert word 返回一个 TrieNode 对象列表,这样我就不必将调用括在方括号(“[”,“]”)中。我认为这是一个错误。
3. 欢迎您就在 F# 中实现此数据结构提供任何其他建议。我知道我一定做错了很多事情,因为我对这种语言非常陌生。例如,我知道单词插入功能有缺陷,因为它不检查列表是否为空,因此它过早结束。当我到达那座桥时,我想越过它。

提前谢谢你

提前谢谢你

【问题讨论】:

  • 不想在没有确定的情况下进行编辑 - 你的意思是一棵树,对吧?列表和二叉树的扩展?
  • 最后的 trie 值最终是类型 (Trie -> Trie) - 这表明它正在部分评估 insertWord
  • 前缀树中的树而不是普通树中的树

标签: f# trie


【解决方案1】:
  1. 您可能无法触发断点,因为您没有完全应用insertWords:它需要两个咖喱参数,但您只传递单个参数wordChars。也许您打算定义您的@987654323 @ 输入这样的代替?

    type Trie(inner : TrieNode) =
      member this.InsertWord(wordChars:char list) = TrieFunctions.insertWord wordChars inner
    
  2. 好吧,您可以将所有返回值包装在 [] 中以使其成为单例列表,然后不包装对 insertWords 的递归调用。但是,您的算法似乎有问题(无论哪种方式),因为您只会得到单例列表...

    请注意,此时您完全放弃了现有的 subnodes 列表 - 如果您想附加到它的前面,请改用 (insertWord wordChards.Tail node)::subnodes。但是,有时您会想要替换现有条目而不是追加新条目,这需要更多的努力。

  3. 有几个问题。以下是一些帮助您入门的方法:

    • 尽量避免使用Head,尤其是当您调用它时,您并不总是知道您的列表是非空的。
    • 当您在空的Trie 中插入一个单词时,您将删除除第一个字符之外的所有字符!同样,您也需要重新考虑递归调用。
    • 更重要的是,你的TrieNode 类型有点问题。您能否写出您希望看到的结果 trie,其中仅包含两个词 "in""to"

【讨论】:

  • 谢谢你的回答,但关于第 2 点单例列表正是我想要避免的,我不知道如何避免它们我想要实际的列表
  • @Para - 如果您解决了第 3 点中的问题,第 2 点应该会自行解决,但我还是添加了一些想法。尝试在纸上浏览一些非常简单的示例。
【解决方案2】:

关于您的第一个问题,正如@kvb 所说,您正在部分应用insertWord。在定义它时,您指定了一个显式参数wordChars,并且通过使用function 构造进行模式匹配,您基本上添加了TrieNode 类型的第二个参数,因此您的函数最终具有以下签名:

insertWord : char list -> TrieNode -> TrieNode

由于在您对InsertWord 的调用(它只是insertWord 的一个包装器)中,您只提供了一个参数(一个字符列表),该函数不会被调用,但您会得到一个需要@ 的函数987654329@回来。 InsertWord 的签名说明了这一点:

InsertWord : wordChars:char list -> (TrieNode -> TrieNode)

注意括号。

您可能希望在您的情况下提供Nil,因为从概念上讲,您正在扩展一个空的 trie:

let trie = Trie(SubNodes(' ',false,List.empty)).InsertWord(['g';'i';'g';'i']) Nil

您可以在此处找到 trie 结构的示例实现:http://lepensemoi.free.fr/index.php/2009/10/15/trie-and-anagrams-with-f

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 2014-06-30
    • 2010-10-15
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多