Как мне добиться того же результата, что и в этот вопрос, используя Haskell и небинарные деревья, такие как Data.Tree
? Учитывая запись NodeData { nodeID :: String , parentID :: String, value :: a }
для хранения данных и Data.Tree
для типа дерева, дерево будет:
Node $ NodeData "id" "parent" (value :: a) (children :: Forest (NodeData a)) :: Tree (NodeData a)
Теперь, как я могу обновить value
на основе дочерних узлов value
и своего собственного? Входная таблица будет списком [NodeData]
. NodeData
, а идентификаторы можно сделать экземпляром Eq
, но не Ord
.
Двоичные деревья поиска поддерживают индексирование во время регистрации; не все деревья должны.
@ThomasM.DuBuisson Нет, я не это имел в виду. NodeData
следует использовать с каким-либо типом Tree a
для создания структуры. Я переписал эту часть вопроса. Возможно, теперь вы понимаете, что я имею в виду.
Я не вижу особенно умного однопроходного решения для этого. Вам просто нужно стиснуть зубы и сделать два прохода: один проход создает индекс формы Map Id [Node]
, в котором перечислены все дочерние элементы каждого узла. Затем второй проход использует этот индекс и преобразует его в Forest a
. Обратите внимание, что это не Tree a
, потому что в корне нет значения, а также потому, что, насколько нам известно, существует несколько корней.
import qualified Data.Map.Lazy as M
import qualified Data.Tree as T
newtype Id = Id Int deriving (Eq, Show, Ord)
data Node a = Node {id, parent :: Id, value :: a} deriving Show
input :: [Node String]
input = [ Node (Id 1) (Id 0) "1"
, Node (Id 2) (Id 1) "1.1"
, Node (Id 3) (Id 0) "2"
, Node (Id 4) (Id 2) "1.1.1"
, Node (Id 5) (Id 3) "2.1"
, Node (Id 6) (Id 1) "1.2"
]
index :: [Node a] -> M.Map Id [Node a]
index m = M.fromListWith (++) $ do
n@(Node this parent v) <- m
pure (parent, [n])
recombine :: M.Map Id [Node a] -> T.Forest a
recombine m = go (Id 0) -- Implied root, but a more thorough solution would be explicit
where go root = [ T.Node v (go idx)
| Node idx p v <- M.findWithDefault [] root m
]
После этого у нас есть дерево, которое мы хотели:
> putStr . T.drawForest . recombine . index $ input
2
|
`- 2.1
1
|
+- 1.2
|
`- 1.1
|
`- 1.1.1
Что, если идентификаторы не могут быть Ord
? Я только что отредактировал вопрос, чтобы сделать это ограничение явным. И как я могу обновить value
на основе детских ценностей?
Если они хэшируемые, вместо этого вы можете использовать хэш-карту. Если они даже не хэшируются, а просто eq, то вы, вероятно, не сможете сделать ничего лучше, чем тот же алгоритм, но с линейным поиском в качестве операции поиска.
И если вы не можете понять, как смотреть на дочерние элементы узла с заданным деревом, вы, вероятно, задаете слишком сложный вопрос, начав с этого дела по реконструкции дерева на основе списка родительских связей.
Я не понимаю. Как это вообще дерево? Я понимаю, что концептуально
NodeData
описывает дерево, но с точки зрения CS нет древоподобных свойств — нет индексации журнала или поиска, вообще нет ссылок. Это просто список ассоциаций, в котором каждый ключ поиска может иметь несколько значений. Вы имели в виду, что NodeData полностью описывает узел ветви дерева?