【问题标题】:Binary tree traversal to enumerate all permutations of Fibonacci values二叉树遍历枚举斐波那契值的所有排列
【发布时间】:2014-07-05 17:08:44
【问题描述】:

我一直在从事这个项目作为一种兴趣,并不断回来......

我正在尝试创建的是一种算法来枚举斐波那契值的二叉树的值集:

我用来打印这棵树的排列的算法:

  1. 打印根值(结果:([root 0]=5))
  2. 下降到左孩子 [left 1]
  3. 打印新的左节点 [left 1] 和右兄弟节点值(结果:([left 1] 3,[right 1] 2))
  4. 如果右兄弟节点 [right 1] 有子节点,遍历这个右节点 [right 1],枚举它的值,连同它的兄弟左节点 [left 1](结果:[left 1] 3,[left 3] 1,[右 3] 1)
  5. 下降到左孩子 [左 2],作为第 2 步
  6. 打印新的左节点值[left 2] 2,以及共同左父节点[left 1]的右兄弟节点值[right 2] 1;同时遍历和枚举根的每一级右节点的结果。因此,在 about 树示例中,枚举结果将是,遍历树以获得排列: ([left 2] 2,[right 2] 1,[right 1] 2),([left 2] 2,[right 2] 1, [左 3] 1, [右 3] 1))
  7. 没有左孩子可以堕落,所以停止

每组应加起来为根的值。我认为我尝试描述算法中每个步骤的方法可能并不完全清楚 - 任何关于在算法中写出步骤的最佳实践的帮助对我也很有用。

我在这里期望的结果,枚举上面的树将是:

([root 0] 5),([left 1] 3, [right 1] 2),([left 1] 3, [left 3] 1, [right 3] 1),([left 2] 2, [右 2] 1, [右 1] 2),([左 2] 2,[右 2] 1, [左 3] 1, [右 3] 1)

我想采用递归方法,并将其作为一种方法合并到我创建的用于构建树的二进制结构类中。所以这不是关于构建树结构,而是按照上面的方法遍历它,或者产生相同结果的方法。

谁能进一步帮助我?任何帮助将不胜感激。

在我的 `FibTree` `Class` 中添加集合打印方法:

FibTree 头文件(代码 sn-ps):

class FibTree {

public:
    class Node {
    public:
    int data;
        Node const* left;
        Node const* right;
        Node const* parent;
        int n;
        int level;
        int index;

        Node (void);

    };

    Node const* root; // 'root' pointer to constant Node
    FibTree (int);
    Node const* getRoot(void);

    void startWriteSets(Node const* root); // Write all sets of tree

private:
    static Node* buildTree( int n, int level = 0, int i = 1, Node* parent = NULL );
    // Used by startWriteSets
    void writeSets(std::vector<Node const*> &setsList, Node const* cur);

FibTree CPP 文件(代码 sn-ps):

// FibTree Constructor
FibTree::FibTree(int n) {
    this->root = buildTree( n );
};

// Getters
FibTree::Node const* FibTree::getRoot(void) {
    return this->root;
}

// Write sets of tree
void FibTree::startWriteSets(Node const* root) {
    std::vector<Node const*> setsList;
    std::cout << root->data;
    writeSets(setsList, root);
}

// Private FibTree methods
FibTree::Node* FibTree::buildTree( int n, int level, int i, Node* parent ) { // Build Tree structure
    Node* thisNode = new Node();
    thisNode->n = n;
    thisNode->level = level;
    thisNode->index = i;
    thisNode->parent = parent;
    if (n < 2) {
         thisNode->left = NULL;
         thisNode->right = NULL;
         thisNode->data = n;
         return thisNode;
    } else {
         thisNode->left = buildTree( n - 1 , level + 1, i*2, thisNode );
         thisNode->right = buildTree( n - 2, level + 1, i*2+1, thisNode );
         thisNode->data = thisNode->left->data + thisNode->right->data;
         return thisNode;
    }
}

void FibTree::writeSets(std::vector<Node const*> &setsList, Node const* cur) {
    std::vector<Node const*>::iterator nodeIterator;

    // Displays all preceding left values
    for (nodeIterator = setsList.begin();
        nodeIterator != setsList.end(); nodeIterator++) {
        std::cout << *nodeIterator->data;
    }   
    std::cout << cur->left->data;
    std::cout << cur->right->data;

    setsList.push_back(cur->left);
    writeSets(setsList,cur->right);
    setsList.pop_back();
}


// FibTree Node constructor
FibTree::Node::Node()
: data( 0 ),
left( NULL ),
right( NULL ),
parent( NULL ),
n( 0 ),
level( 0 ),
index( 0 )
{
};

我在 void FibTree::writeSets 报告中的 std::cout &lt;&lt; *nodeIterator-&gt;data; 上遇到编译错误:

_error: 请求'* nodeIterator 中的成员'data'。 __gnu_cxx::__normal_iterator<_iterator _container>::operator-> with _Iterator = const FibTree::Node**, Container = std::vector >',属于非类类型'const FibTree::Node *'

任何帮助追踪此错误将不胜感激!

【问题讨论】:

  • 把第6步解释清楚。
  • @nikhil_vyas 我已经为我要解决的问题增加了一些清晰度。我不是专业程序员,因此您可能必须将任何建议的方法分解为可理解的块。非常感谢亚历克斯
  • 我已经编辑了我的答案,包括制作套装。
  • 您不能递归地遍历节点并按照您描述的顺序输出节点。您可以做的是分两次执行遍历。使用地图等标准容器有什么限制吗?
  • 我认为您的树还没有完成,或者您计划根据算法添加某种额外的遍历搜索(Left2 必须有 2 个以上的孩子 [left 4] 1, [right 4] 1),如果那是正确的,那么我想我可能会为您提供答案

标签: c++ data-structures binary-tree combinatorics fibonacci


【解决方案1】:

您在这里遇到的问题不是您需要遍历 B-Tree。这是相当直截了当的。您遇到的问题是您需要跟踪等式另一半的状态。 Aka,当你下降到右链的第二层时,你仍然需要知道 [left 1] = 3。

一个可能的解决方案是跟踪向量(或其他构造)中的左节点。所以……

void start(void) {
  vector<NODE*> list;
  cout << head->val;
  visit(list, head);
}

void visit(vector<NODE*> &list, NODE *cur) {
  // Displays all preceding left values.
  for (vector<NODE*> it = list.begin(); it != list.end(); it++) {
    cout << *it->val;
  }
  cout << cur->left->val;
  cout << cur->right->val;

  list.push_back(cur->left);
  visit(list, cur->right);
  list.pop_back();
}

这会在正确的方向上为您提供您正在寻找的东西。您需要添加适当的安全检查和其他方向,但它应该能让您继续前进。

【讨论】:

  • TNX。我在尝试将您的上述建议纳入我的Class FibTree 时遇到了麻烦。在课堂上我有Node const* root; root 被传递给:void FibTree::writeSets(std::vector&lt;Node const*&gt; &amp;setsList, Node const* cur){... 错误 for (std::vector&lt;Node const*&gt; it = setsList.begin(); it != setsList.end(); it++)**error** conversion from '__gnu_cxx::__normal_iterator > >' 到非标量类型 'std::vector >' 请求
  • 它可以为Node const* root 而不是Node* 工作吗?谢谢亚历克斯
  • 抱歉耽搁了。你不应该 for 循环看起来像.... for(vector::iterator it = setsList.begin()...) { 吗?转换错误会让人觉得它是它自己的向量类。
【解决方案2】:

任何树都可以被认为是指向头节点的指针。节点构造函数:

Node(int val,Node* left,Node* right)

树构造函数:

Node* Tree(int n){
    return new Node(fib(n),Tree(n-1),Tree(n-2));
}

这可行,但会具有指数时间复杂度,我建议您使用动态编程来保存以前的树。

现在要按照您所说的进行设置,它们必须求和到根,例如 5 = 3 + 2。在其他集合中,您只需找到将 3 和 2 写为集合的方法。为了找到将 3 作为一个集合编写的方法,您可以递归调用与 5 相同的函数。

vector < vector <int> > SetOfSets(Node * root){
    vector < vector <int> > leftSets = SetOfSets(root.left);
    vector < vector <int> > rightSets = SetOfSets(root.right);
    vector < vector <int> > ans;
    for(int i=0;i<leftSets.size();i++){
        for(int j=0;i<rightSets.size();j++){
            ans.push_back(leftSets[i].insert(leftSet[i].end(),rightSet[j].begin(),rightSet[j].end()));
        }
    }
    return ans;
}

为最终情况添加代码(root.val == 1),您就完成了。

【讨论】:

  • 非常感谢 Nikhil,我已经构建了树,我想这就是构建树。这是否会返回我在示例中列出的所有集合。抱歉,我只是想了解一下。谢谢亚历克斯
【解决方案3】:

考虑节点的结构是:

struct SNode
{
    int m_iValue;
    SNode* m_psLeft;
    SNode* m_psRight;
};

我认为最接近你想要的是:

//returns true if there are still not visited children
bool Traverse(SNode* psNode, int iDepth)
{
    if(iDepth > 0)
    {
        bool bLeftRes;
        if(psNode->m_sLeft != NULL)
        {
            bLeftResult = Traverse(psNode->m_psLeft, iDepth - 1);
        }
        else
        {
            bLeftResult = false;
        }
        bool bRightRes;
        if(psNode->m_sLeft != NULL)
        {
            bRightRes =  Traverse(psNode->m_psRight, iDepth - 1);
        }
        else
        {
            bRightRes = false;
        }
        return bLeftRes || bRightRes;
    }
    else
    {
        printf("%d ", psNode->m_iValue);
        return psNode->m_psLeft || psNode->m_psRight;
    }
}

所以遍历调用看起来像:

int i = 0;
printf("(");
while(Traverse(psRoot, i))
{
    printf(")\n(");
    ++i;
}
printf(")");

输出将与您的树一起: (5) (3 2 ) (2 1 1 1 )

【讨论】:

  • 感谢您提出的解决方案,输出为: (5 ) (3 2 ) (2 1 1 1 ) 建议使用级别顺序广度优先遍历,我需要的解决方案将具有预期的输出如下: (5)(3,2)(3,1,1)(2,1,2)(2,1,1,1) @Aumnayan 建议跟踪向量中的左​​节点
猜你喜欢
  • 1970-01-01
  • 2013-03-14
  • 2012-03-03
  • 2012-03-27
  • 2016-02-21
  • 2015-06-05
  • 1970-01-01
相关资源
最近更新 更多