Как удалить слово из структуры Trie?

Возможно я не достаточно умен, чтобы изучать Хаскелл, но я бы дал ему последний шанс. Я застрял в реализации удаления записи из дерева, структура, похожая на Trie, чтобы быть более конкретной ( http://en.wikipedia.org/wiki/Trie).

Я ищу любые советы (не решение!), Как реализовать такую ​​чистую функцию. У меня была идея об одном алгоритме. Воссоздайте новое дерево, пройдя по всему дереву "пропуская" значения, равные каждому символу слова, при условии, что ребро возвращает исходное дерево, если следующий символ не будет найден. Но возникает проблема, когда персонаж также принадлежит другому слову.

data Trie = Trie { commonness :: Maybe Int
                 , children :: [(Char, Trie)]
                 } deriving (Eq, Read, Show)

-- Creates an empty "dictionary"
trie :: Trie
trie = Trie { commonness = Nothing, children = [] }

-- Inserts a word with given commonness into dictionary
add :: String -> Int -> Trie -> Trie
add [] freq tree
    | (0 <= freq) && (freq <= 16) = tree { commonness = Just freq }
    | otherwise = error $ "Commonness out of bounds: " ++ (show freq)
add word freq tree = tree { children = traverse word (children tree) }
    where
        traverse [] tree = error $ "traverse called with [] " ++ (show tree)
        traverse (x:xs) [] = [(x, add xs freq trie)]
        traverse str@(x:xs) (t:ts)
            | x == fst t = (x, add xs freq $ snd t):ts
            | otherwise = t:(traverse str ts)

remove :: String -> Trie -> Trie
???

И данные выглядят так:

GHCi> putStrLn $ groom $ add "learn" 16 $ add "leap" 5 $ add "sing" 7 $ add "lift" 10 trie

Trie{commonness = Nothing,
     children =
       [('l',
         Trie{commonness = Nothing,
              children =
                [('i',
                  Trie{commonness = Nothing,
                       children =
                         [('f',
                           Trie{commonness = Nothing,
                                children = [('t', Trie{commonness = Just 10, children = []})]})]}),
                 ('e',
                  Trie{commonness = Nothing,
                       children =
                         [('a',
                           Trie{commonness = Nothing,
                                children =
                                  [('p', Trie{commonness = Just 5, children = []}),
                                   ('r',
                                    Trie{commonness = Nothing,
                                         children =
                                           [('n',
                                             Trie{commonness = Just 16, children = []})]})]})]})]}),
        ('s',
         Trie{commonness = Nothing,
              children =
                [('i',
                  Trie{commonness = Nothing,
                       children =
                         [('n',
                           Trie{commonness = Nothing,
                                children =
                                  [('g', Trie{commonness = Just 7, children = []})]})]})]})]}

2 ответа

Это будет проще, если вы используете Map Char Trie вместо [(Char,Trie)] для вашего детского стола. Вот что я собираюсь предположить для этого ответа. Я начну с индуктивного случая:

import qualified Data.Map as Map

remove :: String -> Trie -> Trie
remove (c:cs) t = t { children = Map.alter remove' c (children t) }
    where
    remove' (Just t) = Just (remove cs t)
    remove' Nothing = Nothing
remove [] t = ...

Я оставлю базовый случай для вас. Вот документы для Map Я использовал функцию, изменить. Вы можете получить это же решение без использования Map если вы реализовали alter за [(Char,a)],

Упражнение: remove' довольно многословно Посмотрите, можете ли вы сократить его, используя fmap,

В Python вы можете сделать что-то вроде этого

def remove_string_helper(self, string, pnode, index):
    if pnode:
        flag = False
        if index < len(string):
            flag = self.remove_string_helper(string, pnode.childs.get(string[index]), index + 1)

        if index == len(string) and pnode.is_complete_word:
            pnode.is_complete_word = False
            return len(pnode.childs) == 0

        if flag:
            pnode.childs.pop(string[index])
            return len(self.childs) == 0

    return False

def remove_string(self, string):
    self.remove_string_helper(string, self.childs.get(string[0]), 1)
Другие вопросы по тегам