DS Tree 已知先序、中序 => 建树 => 求后序

参考:二叉树——前序和中序得到后序

思路历程:

在最初敲的时候,经常会弄混preorder和midorder的元素位置。大体的思路就是在preorder中找到根节点(根节点在序列的左边),然后在midorder中找到根节点的位置index,中序序列在index左边的部分就是root的左子树,在index右边的部分就是root的右子树,接着进行递归即可。

在实现的过程中,经常会纠结一个父亲只有一个儿子的时候儿子是左儿子还是右儿子的问题,最后也通过特判root的位置解决了,但是容易混乱。

于是喂了度娘,找到了上面参考的文章,将每一棵树在先序序列的范围,和中序序列的范围作为递归时的参数,这样就很完美的解决了我上面的问题,这种方法比较重要的一点在于求出index来确定左右子树在中序和前序序列中的位置。

代码:

//
//  main.cpp
//  Tree2
//
//  Created by wasdns on 16/12/19.
//  Copyright © 2016年 wasdns. All rights reserved.
//

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

struct Node
{
    int num;
    
    Node *l, *r;
};

int preorder[100005];

int midorder[100005];

int aftorder[100005];

Node *node[100005];

int n;

int tot = 1;    //记录aftorder


/*
    Ininode函数:用于初始化节点
 */
void Ininode()
{
    int i;
    
    for (i = 1; i <= n; i++)
    {
        Node *p = new Node;
        
        p -> num = i;
        p -> l = NULL;
        p -> r = NULL;
        
        node[i] = p;
    }
}

/*
    FindRoot函数:根据先序和中序建树。
 */
Node* FindRoot(int pre_l, int pre_r, int mid_l, int mid_r)
{
    if (pre_r - pre_l < 0) return NULL;
    
    Node* root = new Node;
    
    /*将先序列表中最左边的节点作为root*/
    root -> num = preorder[pre_l];
    
    if (pre_l == pre_r)
    {
        root -> l = NULL;
        root -> r = NULL;
        
        return root;
    }
    
    /*在中序中找到root所在的位置,用index表示*/
    int index;
    
    for (index = mid_l; index <= mid_r; index++)
    {
        if (midorder[index] == preorder[pre_l]) break;
    }
    
    /*说明:利用index进行递归,分成左子树和右子树。        */
    /*同时将先序序列和后序序列进行划分,将位置作为递归的参数。*/
    root -> l = FindRoot(pre_l+1, pre_l+(index-mid_l), mid_l, index-1);
    root -> r = FindRoot(pre_l+(index-mid_l)+1, pre_r, index+1, mid_r);
    
    return root;
}

/*
    CalAftorder函数:根据给定的树来计算后序序列
 */
void CalAftorder(Node *head)
{
    if (head == NULL) return ;
    
    CalAftorder(head -> l);
    CalAftorder(head -> r);
    
    aftorder[tot++] = head -> num;
}


/*
    CalPreorder函数:根据给定的树来计算先序序列
 */
void CalPreorder(Node *head)
{
    if (head == NULL) return ;
    
    preorder[tot++] = head -> num;
    
    CalPreorder(head -> l);
    CalPreorder(head -> r);
}


/*
    Print函数:输出先序、后序序列
 */
void Print()
{
    int i;
    
    for (i = 1; i <= n; i++) {
        cout << preorder[i] << " ";
    }
    
    cout << endl;
    
    for (i = 1; i <= n; i++) {
        cout << aftorder[i] << " ";
    }
    
    cout << endl;
}

int main()
{
    cin >> n;
    
    Ininode();
    
    int i;
    
    for (i = 1; i <= n; i++) {
        cin >> preorder[i];
    }
    
    for (i = 1; i <= n; i++) {
        cin >> midorder[i];
    }
    
    Node *head = new Node;
    
    head = FindRoot(1, n, 1, n);
    
    CalAftorder(head);
    
    Print();
    
    return 0;
}

/*
 7
 5 4 2 3 1 6 7
 4 2 5 1 6 3 7
 */

找了道题试了下水:HDOJ 1710
将上面的代码中的主函数和Print函数做下修改就可以交了:

/*
 Print函数:输出先序、后序序列
 */
void Print()
{
    int i;
    
    for (i = 1; i <= n; i++) {
        
        cout << aftorder[i];
        
        if (i != n) cout << " ";
    }
    
    cout << endl;
}

int main()
{
    while(scanf("%d", &n) != EOF)
    {
        tot = 1;
    
        Ininode();
    
        int i;
    
        for (i = 1; i <= n; i++) {
            cin >> preorder[i];
        }
    
        for (i = 1; i <= n; i++) {
            cin >> midorder[i];
        }
    
        Node *head = new Node;
    
        head = FindRoot(1, n, 1, n);
    
        memset(aftorder, 0, sizeof(aftorder));
        
        CalAftorder(head);
    
        Print();
    }
    
    return 0;
}

2016/12/21

posted @ 2016-12-21 15:41  Wasdns  阅读(683)  评论(0编辑  收藏  举报