重建二叉树专题

重建二叉树

---后序中序--------------------------------------------------------------------------
【一】PAT-A 170304 原题 D
//给出一个树的中序和后序遍历结果,求它的Z字型层序遍历,也就是偶数层从左往右,奇数层从右往左遍历

// 8
// 12 11 20 17 1 15 8 5    中序
// 12 20 17 11 15 8 5 1    后序

// 1 11 5 8 17 12 20 1     zigzagging sequence

#include <cstdio>
#include <queue>
using namespace std;

struct node {
    int data;
    node* l;
    node* r;
    int layer;
};

const int MAXN = 1010;

int N, inOrder[MAXN], postOrder[MAXN], cnt = 0, cnt2 = 0;
node* layerOrder[MAXN];
int leftIndex = 0, rightIndex = 0;

node* create(int inL, int inR, int postL, int postR) {
    if(postL > postR) {
        return NULL;  NULL  NULL  NULL  NULL  NULL
    }
    node* root = new node;
    root->data = postOrder[postR];
    int i;
    for(i=0; i<N; i++) {
        if(root->data == inOrder[i]) break;
    }
    int lenL = i - inL;  // - inL - inL  因为每次的inL不一样,第一次是0,以后就不是了(例如根节点的右子树的左子树的左下标)
    root->l = create(inL,i-1,postL,postL+lenL-1);  // 但是每次的i的值是对的,所以可以直接用i
    root->r = create(i+1,inR,postL+lenL,postR-1);

    return root;
}

void BFS(node* root) {
    queue<node*> q;
    q.push(root);
    root->layer = 1;
    while(!q.empty()) {
        node* now  = q.front();
        layerOrder[cnt++] = now;
        q.pop();
        if(now->l != NULL) {
            q.push(now->l);
            now->l->layer = now->layer + 1;
        }
        if(now->r != NULL) {
            q.push(now->r);
            now->r->layer = now->layer + 1;
        }
    }
}

void print() {
    //printf("\n[%d %d]\n",leftIndex,rightIndex);
    if(layerOrder[leftIndex]->layer % 2 == 0) {
        for(int i=leftIndex; i<=rightIndex; i++) {
            printf("%d",layerOrder[i]->data);
            cnt2++;
            if(cnt2 != cnt) printf(" ");
        }
    } else {
        for(int i=rightIndex; i>=leftIndex; i--) {
            printf("%d",layerOrder[i]->data);
            cnt2++;
            if(cnt2 != cnt) printf(" ");
        }
    }

}

int main() {
	scanf("%d",&N);
	int i;
	for(i=0; i<N; i++) {
		scanf("%d",&inOrder[i]);
	}
	for(i=0; i<N; i++) {
		scanf("%d",&postOrder[i]);
	}
	node* root = create(0,N-1,0,N-1);  //N-1  N-1  N-1  N-1  N-1  N-1
	BFS(root);

    for(i=0; i<N-1; i++) {
        rightIndex = i;
        if(layerOrder[i]->layer != layerOrder[i+1]->layer) {
            print();
            leftIndex = i+1;
        }
    }
    leftIndex = rightIndex;
    rightIndex = cnt - 1;
    //printf("\n[%d %d]\n",leftIndex,rightIndex);
    print();

//    printf("\n");
//	for(i=0; i<N; i++) {
//		printf("%d ",layerOrder[i]->layer);
//	}


	return 0;
}

【二】PAT-A 1020

Sample Input:
7
2 3 1 5 7 6 4	//后序——左子树->右子树->根节点
1 2 3 4 5 6 7	//中序——左子树->根节点->右子树
Sample Output:
4 1 6 3 5 7 2  	//level(层级) order(顺序)

#include <cstdio>
#include <queue>
using namespace std;

const int MAXN = 35;

struct node{
	int data;
	node* lChild;
	node* rChild;
};

int N, postorder[MAXN], inorder[MAXN];

node* create(int postL, int postR, int inL, int inR) {  //create  create  create  create   // 后序区间[postL,postR] 中序区间[inL,inR]
	// 递归边界
	if(postL > postR) {
		return NULL;
	}
	// 新建节点,给新建节点的数据域赋值
	node* root = new node;
	root->data = postorder[postR];
	// 寻找inorder里当前根节点的位置k
	int k;  // k的作用范围 
	for(k=inL; k<=inR; k++) {
		if(inorder[k] == postorder[postR])
			break;
	}
	 计算左子树的结点个数,得到下次递归的后序遍历的左子树的范围:postL, postL + numL - 1, ...
		//(在后续遍历序列中划分左右子树,因为root的左右子树的头结点分别在左右子树序列的最后一个,
		// 所以才有下面的:postL + numL - 1 而不是 postR - 1)
	int numL =  k - inL;
	// 递归式,给新建节点的左右孩子的指针域赋值
	root->lChild = create(postL, postL + numL - 1, inL, k - 1);
		// 如上面所述,注意:create(postL, postR - 1, inL, k - 1); 错 
	root->rChild = create(postL + numL, postR - 1, k + 1, inR);	
		// 若 "..k + 1,.." 写为"inL + k + 1" ,则:递归调用层数太多,提示段错误
	return root;
}

void bfs(node* root) {
	queue<node*> q;  // 注意:node* ,输出时:printf("%d",now->data);
	q.push(root);
	while(!q.empty()) {
		node* now = q.front();  
		printf("%d",now->data);  // 
		q.pop();
		if(now->lChild != NULL)  //
			q.push(now->lChild);
		if(now->rChild != NULL)
			q.push(now->rChild);
		if(!q.empty())  //
			printf(" ");
	}
}

int main() {
	scanf("%d",&N);
	for(int i=0; i<N; i++) {
		scanf("%d",&postorder[i]);
	}
	for(int i=0; i<N; i++) {
		scanf("%d",&inorder[i]);
	}
	// 建树
	node* root = create(0, N-1, 0, N-1);
	// 层序遍历
	bfs(root);

	return 0;
}

---先序中序--------------------------------------------------------------------------
PAT-A 1086

123456的push顺序为先序,pop顺序为中序,求后序

Sample Input:
6
Push 1
Push 2
Push 3
Pop
Pop
Push 4
Pop
Pop
Push 5
Push 6
Pop
Pop
Sample Output:
3 4 2 6 5 1


#include <cstdio>
#include <cstring>
#include <stack>
#include <ostream>
using namespace std;

const int MAXN = 35;

struct node{
    int data;
    node* lChild;
    node* rChild;
};

int N;
int preOrder[MAXN], inOrder[MAXN];
int preL, preR, inL, inR;

node* create(int preL, int preR, int inL, int inR) {
    // 递归边界
    if(preL > preR){
        return NULL;
    }
    // data
    node* root = new node;
    root->data = preOrder[preL];
    // k
    int k;
    for(k=0; k<N; k++) {
        if(preOrder[preL] == inOrder[k])
            break;
    }
    // 计算左子树个数
    int numLeft = k - inL;
    // 递归式
    root->lChild = create(preL+1, preL+numLeft, inL, inL+numLeft-1);
    //或者写 create(preL+1, preL+numLeft, inL, k-1);  都可以,因为numLeft来源于k: numLeft = k - inL
    root->rChild = create(preL+numLeft+1, preR, inL+numLeft+1, inR);
    //或者写 create(preL+numLeft+1, preR, k+1, inR);
    //上面式子最好上下对应写,即:先写先序的左子树和右子树,在写中序的左右

    return root;
}

int j = 1;
void dfs(node* root) {  //左->右->中
    // 递归边界
    if(root == NULL) return;
    // 递归式
    dfs(root->lChild);
    dfs(root->rChild);
    if(j != N){
        printf("%d ",root->data);
        j++;
    } else {
        printf("%d",root->data);
    }

}

int main() {
    scanf("%d",&N);
    stack<int> s;
    char how[5];  //
    int x;
    int j_1 = 0, j_2 = 0;
    for(int i=0; i<N*2; i++) {
        scanf("%s",how);  //
        if(strcmp(how, "Push") == 0) {  //
            scanf("%d",&x);
            preOrder[j_1++] = x;
            s.push(x);
        } else {
            inOrder[j_2++] = s.top();  //
            s.pop();
        }
    }

    node* root = create(0, N-1, 0, N-1);

    dfs(root);

//    for(int i=0; i<N; i++) {
//        printf("%d ",preOrder[i]);
//    }
//    for(int i=0; i<N; i++) {
//        printf("%d ",inOrder[i]);
//    }
    return 0;
}

---层序中序--------------------------------------------------------------------------
ANOJ 180311 模拟 D

给一棵二叉树的层序遍历序列和中序遍历序列,求这棵二叉树的先序遍历序列和后序遍历序列。

7
3 5 4 2 6 7 1
2 5 3 6 4 7 1

3 5 2 4 6 7 1
2 5 6 1 7 4 3

#include <cstdio>

const int maxn = 10010;
int n, num, layer[maxn], in[maxn];

struct tree {
    tree *l, *r;
    int data;
    tree() {
        l = r = NULL;
        data = 0;
    }
};

void PreOrder(tree* root) {
    if(root != NULL) {
        printf("%d",root->data);
        num++;
        if(num != n) printf(" ");
        PreOrder(root->l);
        PreOrder(root->r);
    }
}

void PostOrder(tree * root) {
    if(root != NULL) {
        PostOrder(root->l);
        PostOrder(root->r);
        printf("%d",root->data);
        num++;
        if(num != n) printf(" ");
    }
}

tree* CreateTree(int* layer, int* in, int t) {  //t为当前数组(layer,in)的元素个数
    if(t == 0) return NULL;
    int Llayer[maxn], Rlayer[maxn];
    int Lin[maxn], Rin[maxn];
    tree* node = new tree;
    node->data = layer[0];
    // 在in数组中找出当前根结点的位置
    int i;
    for(i = 0; i < t; i++)
        if(in[i] == layer[0])
            break;
    // 找出in数组中的左子树和右子树
    int cnt = 0;  //count
    for(int j = 0; j < i ; j++)
        Lin[cnt++] = in[j];
    cnt = 0;
    for(int j = i+1; j < t; j++)
        Rin[cnt++] = in[j];
    cnt--;
    // 找出layer数组中的左子树和右子树
    int Llayercnt = 0;
    int Rlayercnt = 0;
    for(int j = 1; j < t ; j++)
        for(int k = 0 ; k < i ; k++)
            if(layer[j] == in[k])
                Llayer[Llayercnt++] = layer[j];
    for(int j = 1; j < t; j++)
        for(int k = i ; k < t; k++)
            if(layer[j] == in[k])
                Rlayer[Rlayercnt++] = layer[j];
    node->l = CreateTree(Llayer,Lin,Llayercnt);
    node->r = CreateTree(Rlayer,Rin,Rlayercnt);
    return node;
}

int main() {
    scanf("%d",&n);
    for(int i=0; i<n; i++) scanf("%d",&layer[i]);
    for(int i=0; i<n; i++) scanf("%d",&in[i]);
    tree* root;  // 或:tree* root = NULL;
    root = CreateTree(layer,in,n);

    num = 0;
    PreOrder(root);
    printf("\n");

    num = 0;
    PostOrder(root);

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值