編程之美 - 重建二叉樹

問題描述: 給出二叉樹先序遍歷和中序遍歷的結果,根據結果重建二叉樹。

舉例: 例如二叉樹


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;
}





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