将多路树转换为左子/右兄弟格式?

时间:2018-12-15 20:51:53

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

我正在尝试编写C ++代码,在给定多路树的情况下,该树会将其转换为left-child/right-sibling format中表示的二进制树。例如,给定这棵树:

          A
        / | \
       B  C  D
     / | \   |
    E  F  G  H
      / \
     I   J

我想输出这棵树:

           A
          /
         B
       /   \
      E     C
       \     \
        F     D
       / \   /
      I   G H
       \
        J

我不确定如何解决此问题。我应该如何考虑呢?

2 个答案:

答案 0 :(得分:0)

您可以使用很好的递归见解来解决此问题。由于我不知道您如何表示树,因此我将让您详细说明如何在代码中实际实现此方法,但这是核心思想。

首先,将一棵空树转换为LC / RS格式真的很容易:它以空树的形式出现。

另一方面,假设您有一棵非空树。首先将其每个子级转换为LC / RS格式(递归)。例如,给定这棵树:

          A
        / | \
       B  C  D
     / | \   |
    E  F  G  H
      / \
     I   J

首先,将每个孩子递归转换为LC / RS,并退还这三棵树:

   B        C         D
  /                  /
 E                  H
  \
   F
  / \
 I   G
  \
   J

这些树目前是自由浮动的,并且彼此之间没有链接。但是,由于您知道它们是兄弟姐妹,因此,您需要使C成为B的正确子代,而D使其成为C的正确子代。从本质上讲,这是一个链表遍历。完成后,事情应该是这样的:

         B
       /   \
      E     C
       \     \
        F     D
       / \   /
      I   G H
       \
        J

完成此操作后,剩下要做的就是使B成为A的左孩子,如下所示:

           A
          /
         B
       /   \
      E     C
       \     \
        F     D
       / \   /
      I   G H
       \
        J

回顾一下,逻辑如下:

  • 如果要转换的树为空,则返回一棵空树。
  • 否则:
    • 将根节点的每个子级递归转换为LC / RS格式。
    • 遍历这些树,分配正确的子链接以将树链接在一起。
    • 将A的左子指针分配为指向结果树(如果没有子树,则为null)。

我将保留C ++详细信息供您填写。如果您试图解决此问题并遇到麻烦,请随时发布后续问题,详细说明您编写的代码到目前为止,还有失败的特定测试用例或您遇到的特定编译器错误。祝你好运!

答案 1 :(得分:0)


假设

假设根据https://en.wikipedia.org/wiki/Binary_tree表示二叉树,而多路树类似于二叉树,但是具有可数的子节点,而不是可选的左右子节点,而算法根据https://en.wikipedia.org/wiki/Left-child_right-sibling_binary_tree


类型

类型可能是以下模板-用于多路树:

template <typename T>
class CMultiWayTree {
public:
    typedef CMultiWayTree<T>*   NodePtr;
    typedef list<NodePtr>       List;
public:
    T                           m_tData;
protected:
    List                        m_lNodes;
public:
    // ...
};

...对于二叉树:

template <typename T>
class CBinaryTree {
public:
    typedef CBinaryTree<T>*     NodePtr;
public:
    typedef CGeneralTree<T>*    MTNodePtr;
public:
    T                           m_tData;
protected:
    NodePtr                     m_pLeftNode;
    NodePtr                     m_pRightNode;
    //...
};

代码

如果假设正确,则代码可能如下所示。而转换算法(“左子级右兄弟二叉树”)是在构造函数“ CBinaryTree(MTNodePtr pmtToConvert)”中实现的。

#include    <iostream>
#include    <list>

using namespace std;

string  ident(int nDepth) {
    string  sIndent;

    for (int n = 0; n < nDepth; n++) {
        sIndent += ' ';
    }
    return sIndent;
}

template <typename T>
class CMultiWayTree {
public:
    typedef CMultiWayTree<T>*   NodePtr;
    typedef list<NodePtr>       List;
public:
    T                           m_tData;
protected:
    List                        m_lNodes;
public:
    CMultiWayTree(const T& rtData) {
        m_tData = rtData;
    };
    virtual ~CMultiWayTree() {
        typename List::iterator it;

        it = m_lNodes.begin();
        while ( it != m_lNodes.end() ) {
            delete (*it);
            it++;
        }
    }
    virtual const T& getNode() { 
        return m_tData;
    };
    virtual void goToFirstChildNode(typename List::iterator& it) { 
        it = m_lNodes.begin();
    };
    virtual void goToNextChildNode(typename List::iterator& it) { 
        it++;
    };
    virtual bool getChildNode(typename List::iterator& it, NodePtr& pNode) { 
        bool    bIsChildNode;

        bIsChildNode = it != (m_lNodes.end());
        if ( bIsChildNode ) {
            pNode = (*it);
        } else {
            pNode = NULL;
        }
        return bIsChildNode;
    };
    virtual NodePtr appendChildNode(const T& rtData) { 
        NodePtr pNode = new CMultiWayTree(rtData);
        m_lNodes.push_back(pNode);
        return pNode;
    };
    virtual void print(ostream& os, int nDepth = 0) { 
        NodePtr     pNode;
        typename List::iterator     it;

        os << ident(nDepth) << m_tData << endl;
        nDepth++;
        goToFirstChildNode(it);
        while ( getChildNode(it, pNode) ) {
            pNode->print(os, nDepth);
            goToNextChildNode(it);
        }
    };
};

template <typename T>
class CBinaryTree {
public:
    typedef CBinaryTree<T>*     NodePtr;
public:
    typedef CMultiWayTree<T>*   MTNodePtr;
public:
    T                           m_tData;
protected:
    NodePtr                     m_pLeftNode;
    NodePtr                     m_pRightNode;
public:
    CBinaryTree(const T& rtData) {
        m_tData = rtData;
        m_pLeftNode = NULL;
        m_pRightNode = NULL;
    };
    CBinaryTree(GTNodePtr pmtToConvert) {
        if ( pmtToConvert != NULL ) {
            NodePtr                                     pNewNode;
            MTNodePtr                                   pNode;
            typename CMultiWayTree<T>::List::iterator   it;

            m_tData = pmtToConvert->m_tData;

            m_pRightNode = NULL;
            pmtToConvert->goToFirstChildNode(it);
            if ( pmtToConvert->getChildNode(it, pNode) ) {
                pNewNode = new CBinaryTree(pNode);
                m_pLeftNode = pNewNode;
                pmtToConvert->goToNextChildNode(it);
            } else {
                m_pLeftNode = NULL;
            }
            while ( pmtToConvert->getChildNode(it, pNode) ) {
                pNewNode = pNewNode->setRight(new CBinaryTree(pNode));
                pmtToConvert->goToNextChildNode(it);
            }
        }
    };
    virtual ~CBinaryTree() {
        if ( m_pLeftNode != NULL ) {
            delete m_pLeftNode;
            m_pLeftNode = NULL;
        }
        if ( m_pRightNode != NULL ) {
            delete m_pRightNode;
            m_pRightNode = NULL;
        }
    };
    virtual NodePtr setRight(NodePtr pNew) {
        if ( m_pRightNode != NULL ) {
            delete m_pRightNode;
        }
        m_pRightNode = pNew;
        return m_pRightNode;
    }
    virtual void print(ostream& os, int nDepth = 0, char chPreFix = '\0') { 
        NodePtr     pNode;

        if ( chPreFix != '\0' ) {
            os << ident(nDepth - 1) << chPreFix << m_tData << endl;
        } else {
            os << ident(nDepth) << m_tData << endl;
        }
        nDepth++;
        if ( m_pRightNode != NULL ) {
            m_pRightNode->print(os, nDepth, 'r');
        }
        if ( m_pLeftNode != NULL ) {
            m_pLeftNode->print(os, nDepth, 'l');
        }
    };
};

int main() {
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNode = new CMultiWayTree<char>('A');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeB = pMultiWayTreeNode->appendChildNode('B');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeC = pMultiWayTreeNode->appendChildNode('C');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeD = pMultiWayTreeNode->appendChildNode('D');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeE = pMultiWayTreeNodeB->appendChildNode('E');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeF = pMultiWayTreeNodeB->appendChildNode('F');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeG = pMultiWayTreeNodeB->appendChildNode('G');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeH = pMultiWayTreeNodeD->appendChildNode('H');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeI = pMultiWayTreeNodeF->appendChildNode('I');
    CMultiWayTree<char>::NodePtr    pMultiWayTreeNodeJ = pMultiWayTreeNodeF->appendChildNode('J');

    cout << "Input (multi-way tree):" << endl;
    pMultiWayTreeNode->print(cout, 3);
    cout << endl;

    CBinaryTree<char>::NodePtr  pBinaryTreeNode = new CBinaryTree<char>(pMultiWayTreeNode);

    cout << "Output (binary tree):" << endl;
    pBinaryTreeNode->print(cout, 3);

    delete pMultiWayTreeNode;
    delete pBinaryTreeNode;

    return 0;
}

输出

程序将创建以下输出:

Input (multi-way tree):
   A
    B
     E
     F
      I
      J
     G
    C
    D
     H

Output (binary tree):
   A
   lB
    rC
     rD
      lH
    lE
     rF
      rG
      lI
       rJ