文章目录
搜索树判断
对于二叉搜索树,我们规定任一结点的左子树仅包含严格小于该结点的键值,而其右子树包含大于或等于该结点的键值。如果我们交换每个节点的左子树和右子树,得到的树叫做镜像二叉搜索树。
现在我们给出一个整数键值序列,请编写程序判断该序列是否为某棵二叉搜索树或某镜像二叉搜索树的前序遍历序列,如果是,则输出对应二叉树的后序遍历序列。
输入格式:
输入的第一行包含一个正整数N(≤1000),第二行包含N个整数,为给出的整数键值序列,数字间以空格分隔。
输出格式:
输出的第一行首先给出判断结果,如果输入的序列是某棵二叉搜索树或某镜像二叉搜索树的前序遍历序列,则输出YES
,否侧输出NO
。如果判断结果是YES
,下一行输出对应二叉树的后序遍历序列。数字间以空格分隔,但行尾不能有多余的空格。
输入样例1:
7
8 6 5 7 10 8 11
输出样例1:
YES
5 7 6 8 11 10 8
输入样例2:
7
8 6 8 5 10 9 11
输出样例2:
NO
思路:
若给定序列是一个二叉搜索树的先序遍历,那么必定满足一个性质,当前这一段数组的第一个一定是当前序列对应子树的根节点,往后比遍历中第一个大于等于子树根的节点p的一定是它的右儿子,并且p节点之后所有节点的数字一定大于等于子树根节点的数字。
那么就先判断这个序列是否满足这个序列,判断镜像二叉树修改一下判断条件就可以了(这里条件写错了,debug了好久)
满足性质后建树并后续遍历输出即可。
网上大多数题解的节点的左右儿子使用指针写的,但是我用不惯,还是直接用下标表示了
两种判断,建树都单独分来写了,代码过于丑陋
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
#include<cstring>
#include<algorithm>
#define fi first
#define se second
#include<stdlib.h>
#include <time.h>
//srand((unsigned)time(NULL));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int N = 1e4 + 10;
const int M = 1e2 + 10;
struct node{
int v;
int l, r;
}tr[N];
int tot;
int newnode() { //动态开点
tot++;
tr[tot].v = tr[tot].l = tr[tot].r =0;
return tot;
}
int n;
int a[N];
bool f1(int l, int r) {
if (l >= r) return true;
bool f = true;
int p = l + 1;
for (p = l + 1; p <= r; p++) { //找到右子树的根节点
if (a[p] >= a[l]) break;
}
for (int i = p + 1; i <= r; i++) { //判断右子树是否满足条件
if (a[i] < a[l]) {
f = false;
break;
}
}
bool fx = f1(l + 1, p - 1);
bool fy = f1(p, r);
if (f && fx && fy) return true; //左右子树包当前子树都满足条件
return false;
}
bool f2(int l, int r) { //同上
if (l >= r) return true;
bool f = true;
int p = l + 1;
for (p = l + 1; p <= r; p++) {
if (a[p] < a[l]) break;
}
for (int i = p + 1; i <= r; i++) {
if (a[i] >= a[l]) {
f = false;
break;
}
}
bool fx = f2(l + 1, p - 1);
bool fy = f2(p, r);
if (f && fx && fy) return true;
return false;
}
int build1(int l, int r) {
int rt = newnode();
tr[rt].v = a[l]; //当前子树的根节点
if (l > r) return 0; //没节点了,直接返回0,这个应该写最前了,但其实也没关系
if (l == r) return rt;
int p = l + 1;
for (p = l + 1; p <= r; p++) {
if (a[p] >= a[l]) break;
}
tr[rt].l = build1(l + 1, p - 1); //建左右子树
tr[rt].r = build1(p, r);
return rt;
}
int build2(int l, int r) { //同上
int rt = newnode();
tr[rt].v = a[l];
if (l > r) return 0;
if (l == r) return rt;
int p = l + 1;
for (p = l + 1; p <= r; p++) {
if (a[p] < a[l]) break;
}
tr[rt].l = build2(l + 1, p - 1);
tr[rt].r = build2(p, r);
return rt;
}
int vis = 0;
void p(int rt) { //后序遍历
if (rt) {
p(tr[rt].l);
p(tr[rt].r);
if (vis++ != 0) printf(" ");
printf("%d", tr[rt].v);
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
if (f1(1, n)) {
printf("YES\n");
tot = vis = 0;
build1(1, n);
p(1);
}
else if (f2(1, n)) {
printf("YES\n");
tot = vis = 0;
build2(1, n);
p(1);
}
else printf("NO\n");
return 0;
}