编程之美 - 重建二叉树

问题描述: 给出二叉树先序遍历和中序遍历的结果,根据结果重建二叉树。

举例: 例如二叉树


pic_1


先序遍历结果 为 abdcef  中序遍历结果为 dbaecf,现根据结果重构二叉树。

思路: 关键需要找到二叉树每一层的根节点和子树的长度。
例如先序遍历中根节点必然是第一个 abdcef ,  通过中序遍历可以发现 dbaecf a的左侧有两个,右侧有3个,说明左子树侧有两个元素,右子树侧有3个元素。
在先序遍历中,挨着a的元素,和与a相聚 pos_a_in_pre+(pos_a_in_mid+1)的元素便是下一层左右子树根的位置
e f。  再依照这个方法递归,就可以重构出二叉树。

示例程序:

typedef struct _node_st
{
    char _data;
    _node_st* _pleft;
    _node_st* _pright;
} node_st;

node_st* rebuild_pre_in1(char* pPreOrder, char* pMidOrder, int nLen)
{
    node_st* pNewNode = NULL;
    int i = 0;
    if ((nLen == 0) || (NULL == pPreOrder) || (NULL == pMidOrder))
    {
        return NULL;
    }

    pNewNode = new node_st();
    pNewNode->_data = pPreOrder[0];

    for (i = 0 ;i < nLen; i++)
    {
        if (pPreOrder[0] == pMidOrder[i])
            break;
    }

    pNewNode->_pleft  = rebuild_pre_in1(pPreOrder+1, pMidOrder, i);
    pNewNode->_pright = rebuild_pre_in1(pPreOrder+1+i, pMidOrder+i+1, nLen-i-1);

    return pNewNode;
}

node_st* rebuild_pre_in2(char* pre, char* mid, int start, int length)
{
    node_st *node;
    int j = 0;
    if ((length <= 0) || ((pre == NULL) || (mid == NULL)))
       return NULL;
    node = new node_st;
    node->_data = pre[start];
    node->_pleft = node->_pright = NULL;
    if (1 == length)
        return node;

    for (j = 0; j < length; j++)
    {
        if (mid[start+j] == node->_data)
            break;
    }
    node->_pleft  = rebuild_pre_in2(pre, mid, start+1, j);
    node->_pright = rebuild_pre_in2(pre, mid, start+(j+1), length-j-1);
    return node;
}

void main()
{
    char pre[] = {'a','b','d','c','e','f'};
    char mid[] = {'d','b','a','e','c','f'};
    int len = sizeof(pre)/sizeof(pre[0]);
    node_st* proot = NULL;
    proot = rebuild_pre_in1(pre, mid, 0, len);
    proot = rebuild_pre_in2(pre, mid, 0, len);
    cin>> len;
}

扩展问题
问题描述: 给出二叉树后序遍历和中序遍历的结果,根据结果重建二叉树。

一棵二叉树后序遍历结果 为 dbefca  中序遍历结果为 dbaecf,现根据结果重构二叉树。
与先序遍历相反,后序遍历的结果根节点在最后一个元素。同样可以根据后序找根节点,根据中序找子树中元素个数。
根节点为 a dbefca, dbaecf a的左侧有两个元素,右边有三个元素,这样可以开始找a 的左/右子树的根节点

因为右子树有三个元素, 在后序遍历的结果中从根节点向前跳过三个元素便是左子树的根了,挨着a的便是右子树的根

pic_2


然后从中序遍历中分别计算出左侧搜索的起始点,和右侧搜索的起点,再找到下一层左右子树的元素个数。


pic_3


示例程序:

typedef struct _node_st
{
    char _data;
    _node_st* _pleft;
    _node_st* _pright;
} node_st;

node_st* rebuild_pst_in1(char* pst, char* mid, int start, int length, int search_start)
{
    node_st *node;
    int j = 0;
    if ((length <= 0) || (start < 0) || ((pst == NULL) || (mid == NULL)))
        return NULL;

    node = new node_st;
    node->_data = pst[start];
    node->_pleft = node->_pright = NULL;

    if (1 == length)
        return node;

    for (j = 0; j < length && (start-j)>=0; j++)
    {
        if (mid[search_start-j] == node->_data)
            break;
    }

    node->_pleft  = rebuild_pst_in1(pst, mid, start-j-1, length-j-1, start-j-1);
    node->_pright = rebuild_pst_in1(pst, mid, start-1, j, length-1);  //  search_start : (length-j-1+j)==> length-1

    return node;
}

void main()
{
    char pre[] = {'a','b','d','c','e','f'};
    char mid[] = {'d','b','a','e','c','f'};
    char pst[] = {'d','b','e','f','c','a'};
    int len = sizeof(pre)/sizeof(pre[0]);
    node_st* proot = NULL;
    proot = rebuild_pst_in1(pst, mid, len-1, len, len-1);
    cin>> len;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章