Inserting a node to highest level node if it is available in Haskell.

huangapple go评论50阅读模式
英文:

Inserting a node to highest level node if it is available in Haskell

问题

I created a tree and its data type is that:

data Tree = Empty | Node Int Int Tree Tree Tree

My first Int is actual data. Second Int is the number of children, meaning this node can store how many children. Even if it is a ternary tree, if the number of children is two, then it should store two children.

My problem is that after I created a function inserter tree node, it will take nodes from a list and it will insert to the highest level node which is available (this means if the number of children is not full still). This is an example:

                              a
                             / \
                            b   c
                           / 
                          d
                         /
                        e

For example, 'd' can store only two children (its second Int value is two), but it has one child. Also, 'b' can store only two children, but it has one child. Now, my list has two nodes, and I will insert these nodes. Firstly, I need to fill 'd', then I will fill 'b' node, so they will reach their number of children. (Let's say my list [k,l]). The end of my process will be that:

                              a
                             / \
                            b   c
                           / \
                          d   l
                         / \
                        e   k

I thought to implement the classic recursive method:

inserter (Node _ num first second third) node
 | num/=0     = Node _ num (inserter first node) (inserter second node) (inserter third node)
 | otherwise  = insert (Node _ num first second third) node

(insert is another function I wrote, and I did the taking from list part to use this function)

When I do that it will insert the first available node, I need to pass until I find the highest level node which is available. Could you give an idea, or a way I can follow?

英文:

I created a tree and its data type is that:

data Tree = Empty | Node Int Int Tree Tree Tree

My first Int is actual data. Second Int is the number of children, meaning this node can store how many children. Even if it is ternary tree, if the number of children is two, then it should store two children.

My problem is that after I created a function inserter tree node, it will take nodes from list and it will insert to the highest level node which is available (this means if number of children is not full still). This is a example:

                              a
                             / \
                            b   c
                           / 
                          d
                         /
                        e

For example, 'd' can store only two children(its second Int value is two), but it has one child. Also, 'b' can store only two children, but it has one child. Now, my list has two node, and I will insert these nodes. Firstly, I need to fill 'd', then I will fill 'b' node, so they will reach their number of children. (Let's say my list [k,l]). The end of my process will be that:

                              a
                             / \
                            b   c
                           / \
                          d   l
                         / \
                        e   k

I thought to implement the classic recursive method:

inserter (Node _ num first second third) node
 | num/=0     = Node _ num (inserter first node) (inserter second node) (inserter third node)
 | otherwise  = insert (Node _ num first second third) node

(insert is other function I wrote, and I did taking from list part to use this function)

When I do that it will insert first available node, I need to pass until found highest level node which is available. Could you give an idea , or a way I can follow?

答案1

得分: 1

将问题拆分成较小的部分。如果 inserter 正在插入一个节点列表,首先尝试编写一个函数(我们称其为 inserter1)仅在最高可用级别插入一个节点。然后你可以根据这个函数编写 inserter

从类型签名开始。我在这里假设当你说“插入一个节点”时,你的意思是“插入一个树”。那么 inserter1 的类型是 Tree -> Tree -> Tree

要定义 inserter1,首先考虑最简单的基本情况,然后从那里开始工作。最简单的情况是插入到一个空树中:

inserter1 :: Tree -> Tree -> Tree
inserter1 Empty node = node

接下来最简单的情况是插入到一个具有一个级别的树中:

inserter1 (Node i n Empty Empty Empty) node
  | n > 0     = Node i n node Empty Empty -- 这里有空间
  | otherwise = _ -- 当没有空间时该怎么做?

在这里我们遇到了一个问题,如果没有空间可以插入东西,应该返回什么。如果 n0,我们不能成功地插入 node!这表明我们应该在返回类型中有一个“无法插入”的概念。对于这种情况,一个常见的模式是使用 Maybe,这意味着将 inserter1 的类型更改为 Tree -> Tree -> Maybe Tree。现在我们可以在第二种情况中返回 Nothing

inserter1 :: Tree -> Tree -> Maybe Tree
inserter1 Empty node = Just node
inserter1 (Node i n Empty Empty Empty) node
  | n > 0     = Just (Node i n node Empty Empty)
  | otherwise = Nothing

递归的情况是在当前级别有多个选择可以插入的情况下,即在这个级别上有可用的 Empty 并且可能更可取的子节点。在这种情况下,我们希望首先尝试插入子节点,只有在插入子节点失败(因为它们已满)时才会在此级别上插入。以下是对一个子节点的处理:

inserter1 (Node i n t1 Empty Empty) node =
  -- 我们应该插入到子节点 `t1` 中还是替换这个级别的一个 `Empty`?首选将其插入子节点中,因此首先尝试这样做。
  case inserter1 t1 node of
    -- 向 `t1` 的插入成功并变为 `t1'`,因此将其替换,我们就完成了!
    Just t1' -> Just (Node i n t1' Empty Empty)
    -- `t1` 必定已满,因此查看此级别是否有空间可以插入
    Nothing
      -- 有空间
      | n > 1 -> Just (Node i n t1 node Empty)
      | otherwise -> Nothing

希望这给了你一些方向,以帮助你完成定义。我建议先为两个非空子节点添加一个情况,然后再为三个非空子节点添加一个情况。尝试让它先正常运行,即使你觉得写了太多的情况也没关系。一旦你有了一些可以运行的东西,通常会更容易看到如何简化它。

英文:

Break the problem down into smaller parts. If inserter is inserting a list of nodes, first try writing a function (let's call it inserter1) that inserts just 1 node at the highest available level. Then you can write inserter in terms of that function.

Start with the type signature. I'm assuming here that when you say "insert a node" you mean "insert a tree". Then inserter1 has type Tree -> Tree -> Tree.

To define inserter1, first think about the simplest base cases and work from there. The simplest case is inserting into an empty tree:

inserter1 :: Tree -> Tree -> Tree
inserter1 Empty node = node

The next simplest case would be inserting into a tree with one level:

inserter1 (Node i n Empty Empty Empty) node
  | n > 0     = Node i n node Empty Empty -- There is room
  | otherwise = _ -- What to do when there is no room? 

Here we run into the question of what to return if there isn't room to insert something. If n is 0, we can't successfully insert node! This suggests we should have a concept of "failing to insert" in the return type. A common pattern for this is to use Maybe, which means change the type of inserter1 to Tree -> Tree -> Maybe Tree. Now we can return Nothing in the second case:

inserter1 :: Tree -> Tree -> Maybe Tree
inserter1 Empty node = Just node
inserter1 (Node i n Empty Empty Empty) node
  | n > 0     = Just (Node i n node Empty Empty)
  | otherwise = Nothing

The recursive case is when you have multiple choices at the current level of where to insert, i.e. there are available Emptys on this level AND child nodes that might be preferable. In this case, we want to try inserting into the child nodes first, and only resort to inserting on this level if inserting into the child nodes fail because they are full. Here is what it looks like for one child node:

inserter1 (Node i n t1 Empty Empty) node =
  -- Should we insert into child `t1` or replace an `Empty` on this level? Inserting into child nodes is preferable, so try it first.
  case inserter1 t1 node of
    -- The insertion to `t1` worked and became `t1'`, so replace it and we're done!
    Just t1' -> Just (Node i n t1' Empty Empty)
    -- `t1` must have been full, so see if there is room to insert on this level
    Nothing
      -- There is room
      | n > 1 -> Just (Node i n t1 node Empty)
      | otherwise -> Nothing

Hopefully this gives some direction to help you complete the definition. I would suggest adding a case for two non-empty children, then for three non-empty children. Try to get it working first, even if it feels like you are writing too many cases. Once you have something working, it is often easier to see how it can be simplified.

huangapple
  • 本文由 发表于 2023年4月17日 04:43:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76030241.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定