让Trie数据结构和添加字符串的函数定义如下:
data Trie = Trie { commonness :: Maybe Int
, children :: [(Char, Trie)]
} deriving (Show, Read, Eq)
-- trie returns an "empty" Trie
trie :: Trie
trie = Trie { commonness = Nothing, children = [] }
-- Add inserts a word to a Trie with a given frequency
-- stored after the last character
add :: String -> Int -> Trie -> Trie
add [] freq tree = tree { commonness = Just freq }
add (x:xs) freq tree = case lookup x (children tree) of
Nothing -> tree { children = (x, add xs freq trie):(children tree) }
Just subtree -> tree { children = (x, add xs freq subtree):(mydrop x (children tree)) }
where
mydrop :: Char -> [(Char, Trie)] -> [(Char, Trie)]
mydrop _ [] = []
mydrop elm (x:xs)
| (fst x) == elm = mydrop elm xs
| otherwise = x:(mydrop elm xs)
如果角色已经存在于当前级别,则问题是关于更好的算法。我想避免调用mydrop函数和重建子列表。
答案 0 :(得分:1)
首先,您可以优化mydrop
函数本身,以便在找到值时停止遍历列表。
但是,恕我直言,优化整个add
函数的唯一方法是合并lookup
并将步骤替换为一次遍历。
add' :: String -> Int -> Trie -> Trie
add' [] freq tree = tree { commonness = Just freq }
add' (x:xs) freq tree =
traverse x (children tree) []
where
traverse x [] ts' = tree { children = (x, add' xs freq trie) : ts' }
traverse x (t:ts) ts' | fst t == x = tree { children = (x, add' xs freq $ snd t) : (ts ++ ts') }
| otherwise = traverse x ts (t:ts')
答案 1 :(得分:1)
如果您使用地图而不是关联列表,则可以在alter
时使用fromMaybe
在查找失败时提供空Trie
:
import qualified Data.Map as Map
import Data.Map ( Map )
import Data.Maybe ( fromMaybe )
data Trie = Trie { commonness :: Maybe Int
, children :: Map Char Trie
} deriving (Show, Read, Eq)
-- trie returns an "empty" Trie
trie :: Trie
trie = Trie { commonness = Nothing, children = Map.empty }
-- Add inserts a word to a Trie with a given frequency
-- stored after the last character
add :: String -> Int -> Trie -> Trie
add [] freq tree = tree { commonness = Just freq }
add (x:xs) freq tree =
tree { children = Map.alter (Just . add xs freq . fromMaybe trie) x $ children tree }