L2-004 这是二叉搜索树吗? (25分)
一棵二叉搜索树可被递归地定义为具有下列性质的二叉树:对于任一结点,
- 其左子树中所有结点的键值小于该结点的键值;
- 其右子树中所有结点的键值大于等于该结点的键值;
- 其左右子树都是二叉搜索树。
所谓二叉搜索树的“镜像”,即将所有结点的左右子树对换位置后所得到的树。
给定一个整数键值序列,现请你编写程序,判断这是否是对一棵二叉搜索树或其镜像进行前序遍历的结果。
输入格式:
输入的第一行给出正整数 N(≤1000)。随后一行给出 N 个整数键值,其间以空格分隔。
输出格式:
如果输入序列是对一棵二叉搜索树或其镜像进行前序遍历的结果,则首先在一行中输出 YES ,然后在下一行输出该树后序遍历的结果。数字间有 1 个空格,一行的首尾不得有多余空格。若答案是否,则输出 NO。
输入样例1
7
8 6 5 7 10 8 11
输出样例1
YES
5 7 6 8 11 10 8
输入样例2
7
8 10 11 8 6 7 5
输出样例2
YES
11 8 10 7 5 6 8
输入样例3
7
8 6 8 5 10 9 11
输出样例3
NO
本题使用递归求解。
输入序列a[0…n]是对树前序遍历的结果,那么a[0]为父(根)结点(的键值),我们首先找出分割其左右子树的一个点,假设该点为m(1<=m<=n),那么a[0]的左子树为a[1…m],右子树为a[m+1…n]。要输出对树进行后序遍历的结果,只需依次输出对a[1…m]后序遍历的结果,对a[m+1…n]后序遍历的结果以及a[0]即可。
如果对于某棵树,我们找不到分割其左右子树的点,说明其不是二叉搜索树,输出NO即可。
#include<stdio.h>
#include<stdlib.h>
int T = 0;
bool isTree=true;
void OUT(int* out, int* a, int l, int r, bool isMirrow)
{
if(isTree==false)return;
if (l > r)return;
if (l == r) {
out[T++] = a[l]; return;
}
int i = 0;
bool lc, rc;
lc = rc = true;
//找到一个i,使得l+1至i所有项小于其父结点的键值(即a[l]),i+1至r所有项大于等于a[l],为镜像时条件相反
//找到之后,有a[l+1]...a[i]为a[l]的左子树,a[i+1]...a[r]为a[l]的右子树
for (i = l; i <= r; i++)
{
lc = rc = true;
for (int j = l + 1; j <= i; j++)
if (isMirrow ? a[j] < a[l] : a[j] >= a[l])
{
lc = false; break;
}
for (int j = i + 1; j <= r; j++)
if (isMirrow ? a[j] >= a[l] : a[j] < a[l])
{
rc = false; break;
}
if (lc && rc)break;
}
if (!lc || !rc){isTree=false;return;} //如果找不到符合条件的i,说明以l为根的子树不是一颗二叉搜索树,将isTree标为false,结束递归
//如果是一颗二叉搜索树,后序遍历其左右子树,并在之后将a[l]写入数组以完成后序遍历
OUT(out, a, l + 1, i, isMirrow); //后序遍历其左子树
OUT(out, a, i + 1, r, isMirrow); //后序遍历其右子树
out[T++] = a[l];
}
int main()
{
int N;
scanf("%d", &N);
int* array = (int*)malloc(sizeof(int) * N);
int* out = (int*)malloc(sizeof(int) * N);
int index = 0;
bool isMirrow = false;
bool turn = false;
scanf("%d", &array[index++]);
int num;
for (int i = 0; i < N - 1; i++)
{
if (i == 0) {
scanf("%d", &num);
if (num >= array[0])isMirrow = true; //第二个接受的值大于等于第一个接受的值时说明该数组是对一棵树的镜像的前序遍历
}
else
scanf("%d", &num);
array[index++] = num;
}
OUT(out, array, 0, index - 1, isMirrow); //以递归方式后序遍历一棵树,将结果写入out数组
if (isTree==false) { printf("NO"); return 0; }//isTree被标记为false说明该树不是二叉搜索树,直接打印NO
printf("YES\n");
if (T > 0)printf("%d", out[0]);
for (int i = 1; i < T; i++) printf(" %d", out[i]);
}