【问题标题】:How do i use doubly(**) pointer in C++ for general tree data structure?如何在 C++ 中将双重(**)指针用于通用树数据结构?
【发布时间】:2014-11-23 23:44:15
【问题描述】:

我有一个结构 s:

struct s{
   int x;
  /********************************************************************
   *  NoOfchild doesn't represent maximum no of children for node s . 
   *  This represent no of children node s have at any given instance . 
   *********************************************************************/      
   int NoOfChild; 
   s  **child;
}

我想用**动态声明指针数组。节点 s 被一一添加到数组中。有什么方法可以实现。这棵树将用于FpGrowth Algorithm

                                         *(0) 
                                           |
          _____________________________________________________________
          |                                |                          | 
       [* (1)                             *(2)                      *(3)]
          |                                |                          |
_______________                    _________________        __________________________
|    |    |   |                   |        |       |        |    |    |     |    |   |
[*   *    *   *]                  [*       *       *]      [*    *    *     *    *   *]

** 代表节点 s 。我不想 declare all children of a node at the same time 即我想添加子节点 one by one ,只要它是 required 。例如o 被添加为根节点,然后节点 1 被添加为根节点的子节点(如果需要),然后节点 2 被添加,依此类推。[* * * * ] 表示节点 x 的子节点。

编辑:
对于给定的节点,人们将 NoOfChild 假设为 maximum no of a child,这是不正确的,这里 NoOfChild 表示一个节点在给定实例中有多少个子节点,它可能会根据要求或时间而有所不同。
说明:强>
最初节点 0 已初始化,因此它有零 (0) 个子节点。
然后将节点 1 添加为节点 0 的子节点,因此 o->NoOfChild = 1 和 1 ->NoOfChild = 0 ;
然后将节点 [*] 添加为节点 1 的子节点,因此 0->NoOfChild = 1 和 1 ->NoOfChild = 1 ;
然后将 2 添加为节点 0 的子节点,因此 0->NoOfChild = 2 和 1 ->NoOfChild = 1 ;
等等。

编辑:
终于用vector<s*> child了。

【问题讨论】:

  • 使用vector<s*>,甚至vector<s>
  • 如果你在 C++ 中做,那么使用向量或列表,而不是数组。节省一些内存和头痛。
  • 是的,这是可能的,但它过于复杂。它是一棵树,而不是一般图,因此您可以使用 s 的数组而不是 s* 的数组,并避免无用的间接寻址。此外,像std::vector 这样的容器会让您省去很多麻烦。
  • @user3919801 然后你可以做类似于std::vector 所做的事情,并分配比你需要的更多,区分“大小”(您存储的实际元素的数量)和“容量”(数量您可以适合分配的元素)。当然,您应该只在 C 中采用这种方法。如果您使用的是 C++,那么您应该只使用 std::vector,正如其他人所指出的那样。
  • 一个简单的想法是指向第一个孩子,如果没有其他孩子,这个孩子指向它的下一个兄弟或自己。

标签: c++ data-structures tree


【解决方案1】:

我用

解决了
struct s{
   int x;
   vector<s*> child ;
}

这更有帮助,因为所有指针/引用都由 STL 管理。

【讨论】:

    【解决方案2】:

    既然你标记了 c++:

    #include <vector>
    #include <memory>
    #include <algorithm>
    #include <iostream>
    
    template <class ValueType>
    class VariadicTree
    {
    public:
        VariadicTree(const ValueType& value) : m_value(value), m_size(0)
        {
        }
    
        VariadicTree<ValueType>& addNode(const ValueType& value)
        {
            m_children.emplace_back(new VariadicTree<ValueType>(value));
            ++m_size;
            return *m_children.back();
        }
    
        bool leaf()
        {
            return std::all_of(m_children.begin(), m_children.end(),
                               [&](const std::unique_ptr<VariadicTree<ValueType>>& ptr)
                                  {return ptr == nullptr;});
        }
    
        size_t size()
        {
            return m_size;
        }
    
        const ValueType& value()
        {
            return m_value;
        }
    
    private:
        size_t m_size;
        const ValueType& m_value;
        std::vector<std::unique_ptr<VariadicTree<ValueType>>> m_children;
    };
    
    int main()
    {
        VariadicTree<int> root(5);
        auto& c1 = root.addNode(4);
        auto& c2 = root.addNode(6);
        auto& c3 = root.addNode(2);
    
        auto& c11 = c1.addNode(2);
    
        std::cout << root.leaf() << "\n";
        std::cout << c11.leaf() << "\n";
        std::cout << root.size() << "\n";
        std::cout << c1.size() << "\n";
        std::cout << c11.size() << "\n";
    
        return 0;
    }
    

    所有权可能可以更优雅地处理,但这应该用于演示目的。

    【讨论】:

    • 再次阅读问题:/
    • @user3919801 现在好点了吗?当然,出于其他列出的原因,我没有使用双指针。
    【解决方案3】:

    纯 c 版本:

    struct node
    {
        int key;
        int noOfChild;
        struct node** childrenArray;
    };
    
    struct node* newNode(int key, int noOfChild)
    {
        int i;
        struct node* node = (struct node*) malloc(sizeof(struct node));
        node->key = key;
        node->noOfChild = noOfChild;
        node->childrenArray = (struct node**) malloc(noOfChild * sizeof(struct node*));
        for(i=0;i<noOfChild;i++)
        {
            node->childrenArray[i] = NULL;
        }
        return(node);
    }
    

    【讨论】:

    • 我误会了什么?
    • 你假设一个节点的所有子节点都被声明一次。
    【解决方案4】:

    第一个答案是:你不知道。像所指示的 cmets 中的每个人一样使用容器类。

    第二个答案是:动态分配:

    void addNewChild(s *into, s* new_child)
    {
       s **tmp_s = new s*[into->NoOfChild+1];    ///< will throw if allocation fails
    
       for(int i=0; i<into->NoOfChild; i++) tmps[i] = into->child[i];  ///< use a memcpy instead
       tmps[into->NoOfChild++] = new_child;
    
       s **del_s = into->child;
       into->child = tmp_s;
       delete[] del_s;
    }
    

    最后:不要这样做。使用std::vector&lt;s&gt;std::vector&lt;s*&gt;,具体取决于孩子可以拥有多少父母。

    【讨论】:

    • 最后使用 std::vector 或 std::vector :p 在挖矿中我们不知道一个人可以提前拥有多少个孩子,这完全取决于输入数据。
    • 我建议使用std::vector&lt;s*&gt;,因为vector复制了push_back()-ed的对象。如果s 是树状结构的类,则复制对象本身将是一个纯粹的地狱(因为s 对象包含其他s 对象的向量......)
    • 在 C++ 中,如果您正在做一些可以用标准容器完成的事情,您需要证明为什么不能将它们用于您的应用程序。他们是“道路”,那些漫无目的地从道路上徘徊的人会被恐惧和怜悯。 :)
    • vector&lt;s&gt;bad idea
    • 呵呵...今天学到了新东西。根据 C++03 标准,显然struct s { ...; vector&lt;s&gt; child; } 是明确非法的。这也是一个坏主意,因为添加一个新孩子会导致大量的重新分配。新的移动语义(我认为是 X++11)可能会限制这种效果,但这并不重要,因为即使在 C++14 标准中它似乎仍然是 UB。
    【解决方案5】:

    对于一般的树数据结构,您可以使用:-

     struct tree{
     int element;
     struct tree *firstchild;
     struct tree *nextsibling;
     };
    

    元素包含要插入到节点的数据。

    FirstChild 包含节点的第一个子节点。

    nextsibling 包含同一父节点的另一个子节点。 示例:-

       A
    
     B  C  D
    
    EF  G     H
    

    那么 A->firstchild = B; B->nextsibling=C; C->nextsibling=D; B->firstchild=E; E->nextsibling=F; C->firstchild=g; D->firstchild=H;

    其他未指定的值可以作为NULL;

    【讨论】:

    • 我不...什么?你在写这个答案的过程中不小心点击了保存吗?
    • @Ajay 不想使用 firstchild , nextsibling 节点结构。
    • 原来空答案的想法是什么?只是把东西放在第一位?
    • 看起来 OP 不是在寻找二叉树数据结构,所以您可能需要重新考虑您的答案
    • @user3919801 阅读问题下的 cmets。孩子们的自然选择是std::vector&lt;a&gt;。它管理重新分配并跟踪数字。很难找到不使用它的理由。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-25
    • 2011-11-30
    相关资源
    最近更新 更多