Как функционально генерировать широту дерева - сначала. (С haskell)

StackOverflow https://stackoverflow.com/questions/2838670

Вопрос

Скажем, у меня есть следующий тип Haskell Tree, где «состояние» - это простая обертка:

data Tree a = Branch (State a) [Tree a]
            | Leaf   (State a)
            deriving (Eq, Show)

У меня также есть функция «Развернуть :: Дерево A -> Дерево A», которое принимает узел листьев и расширяет его в ветку, или принимает ветку и возвращает его неизменным. Этот тип дерева представляет собой N-ary поиска.

Глубина поиска - сначала - это отходы, поскольку пространство поиска, очевидно, бесконечна, так как я могу легко продолжать расширять поисковую площадку с использованием расширения на всех узлах листа дерева, а также шансы случайно отсутствуют. Огромно ... Таким образом, единственное решение - первый поиск в ширине, реализован довольно приличным здесь, что найдет решение, если он там.

Что я хочу Для генерации, хотя дерево пройдено вплоть до нахождение решения. Это проблема, потому что я только знаю, как это только для этой глубины, которая может быть сделана, просто называемая функцией «Развернуть» снова и снова на первом узере дочернего ребенка ... пока не будет найден цель. (Это действительно не генерирует ничего другого, то действительно неудобный список.)

Может ли кто-нибудь дать мне какие-либо намеки на то, как сделать это (или целый алгоритм), или приговор о том, возможно ли можно с приличной сложностью? (Или какие-либо источники на это, потому что я нашел довольно мало.)

Это было полезно?

Решение

Вы смотрели на Крис Окасаки «Ширина первого нумерации: уроки из небольших упражнений в алгоритме Дизайн»? То Data.Tree Модуль включает в себя монадический построитель дерева с именем unfoldTreeM_BF Это использует алгоритм, адаптированный из этой статьи.

Вот пример, который я думаю, соответствует тому, что вы делаете:

Предположим, я хочу найти бесконечное двоичное дерево строк, где все левые дети - родительская строка плюс «а», а вправо дети являются родителями плюс «BB». Я мог бы использовать unfoldTreeM_BF Чтобы найти широту дерева - сначала и верните дерево искали до решения:

import Control.Monad.State
import Data.Tree

children :: String -> [String]
children x = [x ++ "a", x ++ "bb"]

expand query x = do
  found <- get
  if found
    then return (x, [])
    else do
      let (before, after) = break (==query) $ children x
      if null after
        then return (x, before)
        else do
          put True
          return (x, before ++ [head after])

searchBF query = (evalState $ unfoldTreeM_BF (expand query) []) False

printSearchBF = drawTree . searchBF

Это не очень красиво, но это работает. Если я ищу «AABB», я получаю именно то, что я хочу:

|
+- a
|  |
|  +- aa
|  |  |
|  |  +- aaa
|  |  |
|  |  `- aabb
|  |
|  `- abb
|
`- bb
   |
   +- bba
   |
   `- bbbb

Если это то, что вы описываете, вам не должно быть трудно адаптироваться к вашему типу дерева.

Обновление: вот бесплатная версия expand, если вы в таком видах вещи:

expand q x = liftM ((,) x) $ get >>= expandChildren
  where
    checkChildren (before, [])  = return before
    checkChildren (before, t:_) = put True >> return (before ++ [t])

    expandChildren True  = return []
    expandChildren _     = checkChildren $ break (==q) $ children x

(Благодаря Camccann для подталкивания меня от старых привычек структуры управления. Я надеюсь, что эта версия более приемлема.)

Другие советы

Мне любопытно, почему вам нужен expand Функция вообще - почему бы не просто строить все дерево рекурсивно и выполнить все, что вы хотите?

Если вы используете expand Для того, чтобы отслеживать, какие узлы проверяются поиском, построение списка, как вы идете, кажется проще или даже вторая древовидная структура.

Вот быстрый пример, который просто возвращает первый результат, который он находит, с ложным Leaf Конструктор удален:

data State a = State { getState :: a } deriving (Eq, Show)

data Tree a = Branch { 
    state :: State a, 
    children :: [Tree a]
    } deriving (Eq, Show)

breadth ts = map (getState . state) ts ++ breadth (concatMap children ts)
search f t = head $ filter f (breadth [t])

mkTree n = Branch (State n) (map mkTree [n, 2*n .. n*n])

testTree = mkTree 2

Пробуя это в ГХCi:

> search (== 24) testTree
24

Напротив, вот наивный поиск по глубину, первый поиск:

depth (Branch (State x) ts) = x : (concatMap depth ts)
dSearch f t = head $ filter f (depth t)

... который, конечно, терпеет неудачу при поиске с (== 24), потому что левые ветки - бесконечная серия из 2s.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top