[英]F# compute height of a trie node
我正在嘗試使用一種計算每個節點的高度的方法在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) -> if subnodes.Length > 0 then [ (List.filter(fun (this:TrieNode) -> this.Char = c) subnodes).Head ] else []
member this.AWordEndsHere = match this with | Nil -> false
| SubNodes(c,weh,subnodes) -> weh
module TrieFunctions =
let rec insertWord (wordChars:char list) = function
| Nil -> SubNodes(' ', false, (insertWord wordChars Nil)::[])
//daca aici inca nu e cel putin un nod atunci fa nodul radacina standard adica nodul care nu e sfarsit de cuvant si
//are caracterul ' ' si incepe sa ii construiesti lui subnodurile
| SubNodes(c, weh, subnodes) as node ->
if(wordChars.Length = 1) then
SubNodes(wordChars.Head,true,[])
else
let child = node.GetChild(wordChars.Head)
if child = [] then
SubNodes(wordChars.Head,false,(insertWord wordChars.Tail node)::subnodes )
else
SubNodes(wordChars.Head,false,(insertWord wordChars.Tail child.Head)::subnodes )
let stringToCharList(s:string) = List.ofSeq s
type Trie(inner : TrieNode) =
member this.InsertWord(wordChars:char list) = Trie(TrieFunctions.insertWord wordChars inner)
member this.InsertWord(str:string) = Trie(TrieFunctions.insertWord (TrieFunctions.stringToCharList str) inner)
let trie = Trie(SubNodes(' ',false,List.empty))
.InsertWord("abc")
.InsertWord("abcd")
.InsertWord("abcd")
.InsertWord("abcde")
.InsertWord("abcdef")
.InsertWord("ab123cd")
.InsertWord("abc123d")
.InsertWord("abc132d")
現在,我正在嘗試編寫高度計算功能。 如果這是一個二叉樹,這將很容易編寫,但是在此樹中,每個節點都有一個子節點列表,所以我不知道如何循環遍歷F#中的東西。
到目前為止,這是我使用列表折疊操作想到的,但是無法編譯:
module NodeFunctions =
let rec nextLevel(node:TrieNode,curlevel:int) = function
| Nil -> curlevel
| SubNodes(_,_,subnodes) ->
List.fold (fun acc (node:TrieNode,_,_) -> let res = nextLevel(node,curlevel+1) and
if( acc > res) then acc else res) curlevel subnodes
有什么想法可以重寫此功能以使其起作用嗎? 或關於如何實現我的目標的任何想法都不應該是正確的想法嗎?
先感謝您
您的代碼似乎幾乎是正確的。 以下代碼為我編譯(我沒有嘗試運行它,因為在創建trie
值時遇到異常,但是遞歸方案聽起來不錯):
let rec nextLevel(node:TrieNode,curlevel:int) =
match node with
| Nil -> curlevel
| SubNodes(_,_,subnodes) ->
List.fold (fun acc (node:TrieNode) ->
let res = nextLevel(node,curlevel+1)
if (acc > res) then acc else res) curlevel subnodes
我所做的更改:
您編寫了nextLevel(...) = function ...
function
構造創建一個帶有一些值和模式匹配的函數(因此您編寫了TrieNode
兩個TrieNode
參數的函數)。 我用簡單的match
代替了它。
在您的lambda中, let res = nextLevel(node,curlevel+1) and
- and
關鍵字不屬於那里(您可以在其中編寫let res = .. in
但由於縮進而沒有必要)。
您的lambda函數使用模式匹配來提取元組的元素(node:TrieNode,_,_)
,但是subnodes
不是元組列表, TrieNode
只是TrieNode
值列表。
這是更具功能性的代碼布局。 與您的代碼相同的邏輯。 我正在研究一種可行的解決方案。
module Trie =
type Node = Node of (char * bool * Node list) Option
let char = function
| Node(None) -> ' '
| Node(Some(c, _, _)) -> c
let getChild (c:char) = function
| Node(None) -> None
| Node(Some(c, weh, subnodes)) ->
List.tryFind (fun (node:Node) -> (char node) = c) subnodes
let rec insertWordChars (wordChars:char list) = function
| Node(None) -> Node(Some(wordChars.Head, false, [insertWordChars wordChars.Tail (Node(None))]))
| Node(Some(c, weh, subnodes)) as node ->
if wordChars.Length = 1 then
Node(Some(wordChars.Head, true, []))
else
match getChild (wordChars.Head) node with
| None -> Node(Some(wordChars.Head, false, (insertWordChars wordChars.Tail node)::subnodes))
| Some(child) -> Node(Some(wordChars.Head, false, (insertWordChars wordChars.Tail child)::subnodes))
let insertWord (s:string) = insertWordChars (List.ofSeq s)
打印高度。
let rec nextLevel (curlevel:int) = function
| Trie.Node(None) -> curlevel
| Trie.Node(Some(_, _, subnodes)) ->
List.fold (fun acc (node:Trie.Node) ->
let res = nextLevel (curlevel + 1) node
if (acc > res) then acc else res) curlevel subnodes
let trie =
Trie.Node(Some(' ', false, []))
|> Trie.insertWord("abc")
|> Trie.insertWord("abcd")
|> Trie.insertWord("abcd")
|> Trie.insertWord("abcde")
|> Trie.insertWord("abcdef")
|> Trie.insertWord("ab123cd")
|> Trie.insertWord("abc123d")
|> Trie.insertWord("abc132d")
printf "%A" (nextLevel 0 trie)
我會采取另一種方法:
let rec depth = function
| Nil -> 0
| SubNodes(_,_,l) ->
let d = l |> List.map depth |> List.max
d + 1
對我來說,這比使用fold的版本更容易閱讀,盡管它確實遍歷了子節點列表兩次。
再想一想Trie,您最初的方法很接近,但要求所有內容都以同一字母開頭。 這是一個可以正常使用的特里,它使用像您的原始想法一樣的字符而不是字符串。 我將它留給讀者作為練習來實現字符串節點和葉子。
module Trie =
type Node = Node of (char * bool * Node) list
let empty = Node([])
let partition c = function
| Node(nodes) -> List.partition (fun (ct, _, _) -> ct = c) nodes
let rec insert wordChars node =
match wordChars, node with
| c::cx, Node([]) -> Node([c, cx.IsEmpty, (insert cx empty)])
| c::cx, _ ->
match partition c node with
| (ct, weh, children)::_, others ->
Node((c, (weh || cx.IsEmpty), insert cx children)::others)
| [] , others ->
Node((c, cx.IsEmpty, insert cx empty)::others)
| [], _ -> node
let insertWord (s:string) node = insert (List.ofSeq s) node
和一些測試
let rec nextLevel (curlevel:int) = function
| Trie.Node([]) -> curlevel
| Trie.Node(nodes) ->
List.fold (fun acc (_, _, node) ->
let res = nextLevel (curlevel + 1) node
if (acc > res) then acc else res) curlevel nodes
let rec print acc = function
| Trie.Node(nodes) ->
List.iter (fun (c, w, node) ->
let str = acc + c.ToString()
if w then printfn "%s" str
print str node) nodes
let trie =
Trie.empty
|> Trie.insertWord("abc")
|> Trie.insertWord("abcd")
|> Trie.insertWord("abcd")
|> Trie.insertWord("abcde")
|> Trie.insertWord("abcdef")
|> Trie.insertWord("ab123cd")
|> Trie.insertWord("abc123d")
|> Trie.insertWord("abc132d")
printf "%d\n" (nextLevel 0 trie)
print "" trie
輸出量
7
abc
abc132d
abc123d
abcd
abcde
abcdef
ab123cd
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.