二叉树遍历以枚举Fibonacci值的所有排列

时间:2014-05-17 07:54:57

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

我正在进行这个项目的兴趣,并继续回到它...

我尝试创建的是一种枚举Fibonacci值二叉树值的算法:

Fibonacci tree values

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

  1. 打印根值(结果:([root 0] = 5))
  2. 下降到左边的孩子[左1]
  3. 打印新左节点[左1]和右兄弟节点值(结果:([左1] 3,[右1] 2))
  4. 如果右兄弟节点[右1]有子节点,则遍历此右节点[右1],枚举它的值,以及它的兄弟节点左节点[左1](结果: [左1] 3,[左3] 1,[右3] 1)
  5. 下降到左边的孩子[左2],如第2步
  6. 打印新左侧节点值[左侧2] 2,右侧共同左侧父节点右侧[右侧2] 1 [左侧1];同时遍历和枚举根的每个级别的右边节点的结果。因此在约束树示例中,枚举结果将遍历树以获得排列:([left 2] 2,[right 2] 1,[right 1] 2),([left 2] 2,[right] 2] 1,[left 3] 1,[right 3] 1))
  7. 没有留下孩子,所以停止
  8. 每个集合应该加起来为root的值。我认为我尝试描述算法中每个步骤的方法可能并不完全清楚 - 在编写算法步骤的最佳实践方面的任何帮助对我都有用。

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

    ([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)

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

    有人可以帮助我吗?任何帮助将不胜感激。

    将set打印方法添加到我的`FibTree``Class`:

    FibTree头文件(代码片段):

    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文件(代码段):

    // 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 )
    {
    };
    

    我在std::cout << *nodeIterator->data;报告中void FibTree::writeSets收到编译错误:

    _error:请求成员&#39;数据& #39;在&#39; * nodeIterator中。 __gnu_cxx :: __ normal_iterator&lt; _Iterator,_Container&gt; :: operator-&gt;使用_Iterator = const FibTree :: Node **, Container = std :: vector&gt;&#39;,这是非类型的&#c; const FibTree :: Node *&#39;

    非常感谢任何追踪此错误的帮助!

3 个答案:

答案 0 :(得分:1)

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

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

树构造函数:

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

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

现在按照你的说法设置它们必须总结为root,例如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),您就完成了。

答案 1 :(得分:1)

你遇到的问题不是你需要遍历B树。这是相当直接的。你遇到的问题是你需要跟踪方程的另一半的状态。 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();
}

这会在正确的方向上为您提供所需的信息。您需要添加适当的安全检查和其他方向,但它应该让您前进。

答案 2 :(得分:0)

考虑节点的结构是:

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)