二叉树的按层打印与ZigZag打印

二叉树的按层打印与ZigZag打印

题目描述:

给定一颗二叉树,分别实现按层和 ZigZag 打印二叉树。

ZigZag遍历: 意思是第一层从左到右遍历,第二层从右到左遍历,依次类推。

输入描述:

第一行输入两个整数 n 和 root,n 表示二叉树的总节点个数,root 表示二叉树的根节点。
以下 n 行每行三个整数 fa,lch,rch,表示 fa 的左儿子为 lch,右儿子为 rch。(如果 lch 为 0 则表示 fa 没有左儿子,rch同理)

输出描述:

先输出按层打印,再输出按ZigZag打印。

示例1
输入
8 1
1 2 3
2 4 0
4 0 0
3 5 6
5 7 8
6 0 0
7 0 0
8 0 0
输出
Level 1 : 1
Level 2 : 2 3
Level 3 : 4 5 6
Level 4 : 7 8
Level 1 from left to right: 1
Level 2 from right to left: 3 2
Level 3 from left to right: 4 5 6
Level 4 from right to left: 8 7
备注:

1 ≤ n ≤ 5 ∗ 1 0 5 1 \leq n \leq 5*10^5 1n5105

1 ≤ f a , l c h , r c h , r o o t ≤ n 1 \leq fa,lch,rch,root \leq n 1fa,lch,rch,rootn


题解:

对于层次打印,因为需要分层输出,需要记录每层层最后进入队列的节点,如果队列中弹出的节点等于这个节点,则需要换行。

对于 ZigZag 打印,同样需要记录每层最后一个节点。我们可以使用双端队列进行处理:

  • 从左到右过程:弹出队列头部节点,将节点的左儿子、右儿子先后压入队列的尾部;
  • 从右到左过程:弹出队列尾部节点,将节点的右儿子、左儿子先后压入队列的首部;

注意:换行时,第一个进入队列的节点是下一层最后一个打印的节点。

代码:
#include <cstdio>
#include <queue>
#include <deque>

using namespace std;

const int N = 500010;

struct BST {
    int val, lch, rch;
} bst[N];

int n, rt;
int fa, lch, rch;

void printByLevel() {
    queue<int> q;
    int last = rt;
    int nLast = 0;
    q.push(rt);
    int level = 0;
    printf("Level %d :", ++level);
    while (!q.empty()) {
        int t = q.front();
        q.pop();
        printf(" %d", bst[t].val);
        if (bst[t].lch) {
            q.push(bst[t].lch);
            nLast = bst[t].lch;
        }
        if (bst[t].rch) {
            q.push(bst[t].rch);
            nLast = bst[t].rch;
        }
        if (t == last && !q.empty()) {
            printf("\nLevel %d :", ++level);
            last = nLast;
        }
    }
    puts("");
}

void printZigZag() {
    int last = rt;
    int nLast = 0;
    bool flag = true;
    deque<int> dq;
    dq.push_front(rt);
    int level = 0;
    int now;
    printf("Level %d from left to right:", ++level);
    while (!dq.empty()) {
        if (flag) {
            now = dq.front();
            dq.pop_front();
            if (bst[now].lch) {
                dq.push_back(bst[now].lch);
                if (!nLast) nLast = bst[now].lch;
            }
            if (bst[now].rch) {
                dq.push_back(bst[now].rch);
                if (!nLast) nLast = bst[now].rch;
            }
        } else {
            now = dq.back();
            dq.pop_back();
            if (bst[now].rch) {
                dq.push_front(bst[now].rch);
                if (!nLast) nLast = bst[now].rch;
            }
            if (bst[now].lch) {
                dq.push_front(bst[now].lch);
                if (!nLast) nLast = bst[now].lch;
            }
        }
        printf(" %d", bst[now].val);
        if (last == now && !dq.empty()) {
            printf("\nLevel %d from ", ++level);
            if (flag) printf("right to left:");
            else printf("left to right:");
            flag = !flag;
            last = nLast;
            nLast = 0;
        }
    }
}

int main(void) {
    scanf("%d%d", &n, &rt);
    while (n--) {
        scanf("%d %d %d", &fa, &lch, &rch);
        bst[fa].val = fa;
        bst[fa].lch = lch;
        bst[fa].rch = rch;
    }
    printByLevel();
    printZigZag();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值