先序和后序序列创建二叉树

先序+中序,后序+中序创建二叉树的关键在于,使用分治思想,先在先序或后序中找到当前子树的根节点,并在中序中找到位置,来划分左右子树区间

// pre与in不仅表示先序中序序列,同时也表示当前子串的开头,n为当前子串长度
Node* creat_pre_in(char *pre, char *in, int n){ // 先序加中序
    Node *s; char *p; int k;
    if (n <= 0)
        return NULL;
    s = new Node(); // 创建根节点
    s->val = *pre; // 先序第一个节点为当前根节点
    for (p = in; p < in+n; p++) // 找到根节点在中序中位置
        if (*p == *pre)
            break;
    k = p-in; // k表示左串长度
    // 划分左右子串,递归创建左右子树
    s->lchild = creat_pre_in(pre+1, in, k);
    s->rchild = creat_pre_in(pre+k+1, in+k+1, n-k-1);
    return s;
}

先序+后续与其类似,但有所不同的是,选择先序的第一个字符作为根节点后,需要选择先序第二个字符,在后序中寻找,来划分区间

因此当区间只有一个节点时,需要直接返回当前节点,无节点时仍需返回空指针

// 与前面不同的是,当只有一个节点时,无法找到pre+1位置,此时直接返回节点
Node* creat_pre_post(char *pre, char *post, int n){ // 先序+后序
    Node *s; char *p; int k;
    if (n <= 0)
        return NULL;
    s = new Node();
    s->val = *pre;
    if (n == 1)
        return s;
    for (p = post; p < post+n; p ++)
        if (*p == *(pre+1))
            break;
    k = p-post+1;
    s -> lchild = creat_pre_post(pre+1, post, k);
    s -> rchild = creat_pre_post(pre+k+1, post+k, n-k-1);
    return s;
}

完整代码:

# include <bits/stdc++.h>

using namespace std;

const int N = 1003;

struct Node{
    char val;
    Node *lchild, *rchild;
};

// pre与in不仅表示先序中序序列,同时也表示当前子串的开头,n为当前子串长度
Node* creat_pre_in(char *pre, char *in, int n){ // 先序加中序
    Node *s; char *p; int k;
    if (n <= 0)
        return NULL;
    s = new Node(); // 创建根节点
    s->val = *pre; // 先序第一个节点为当前根节点
    for (p = in; p < in+n; p++) // 找到根节点在中序中位置
        if (*p == *pre)
            break;
    k = p-in; // k表示左串长度
    // 划分左右子串,递归创建左右子树
    s->lchild = creat_pre_in(pre+1, in, k);
    s->rchild = creat_pre_in(pre+k+1, in+k+1, n-k-1);
    return s;
}

Node* creat_in_post(char *post, char *in, int n){ // 后序加中序
    Node *s; char r, *p; int k;
    if (n <= 0)
        return NULL;
    s = new Node();
    r = *(post+n-1);
    s->val = r;
    for(p = in; p < in+n; p ++)
        if (*p == r)
            break;
    k = p-in;
    s -> lchild = creat_in_post(post, in, k);
    s -> rchild = creat_in_post(post+k, in+k+1, n-k-1);
    return s;
}

// 与前面不同的是,当只有一个节点时,无法找到pre+1位置,此时直接返回节点
Node* creat_pre_post(char *pre, char *post, int n){ // 先序加后序
    Node *s; char *p; int k;
    if (n <= 0)
        return NULL;
    s = new Node();
    s->val = *pre;
    if (n == 1)
        return s;
    for (p = post; p < post+n; p ++)
        if (*p == *(pre+1))
            break;
    k = p-post+1;
    s -> lchild = creat_pre_post(pre+1, post, k);
    s -> rchild = creat_pre_post(pre+k+1, post+k, n-k-1);
    return s;
}

void bfs_level(Node *T){ // 层序遍历
    queue<Node*> q;
    q.push(T);
    while (!q.empty()){
        Node *p = q.front(); q.pop();
        cout << p->val << " ";
        if (p->lchild) q.push(p->lchild);
        if (p->rchild) q.push(p->rchild);
    }
    puts("");
}

int main(){
    int n;
    char a[N], b[N];
    cin >> n;
    cin >> a;
    cin >> b;
    Node *T = creat_pre_post(a, b, n);
    bfs_level(T);
    return 0;
}

/*
先后
7
ABDGECF
GDEBFCA

前中
7
ABDGCEF
DGBAECF

后中
7
GDBEFCA
DGBAECF

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值