A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:
- The left subtree of a node contains only nodes with keys less than the node's key.
- The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
- Both the left and right subtrees must also be binary search trees.
If we swap the left and right subtrees of every node, then the resulting tree is called the Mirror Image of a BST.
Now given a sequence of integer keys, you are supposed to tell if it is the preorder traversal sequence of a BST or the mirror image of a BST.
Input Specification:
Each input file contains one test case. For each case, the first line contains a positive integer N (≤1000). Then N integer keys are given in the next line. All the numbers in a line are separated by a space.
Output Specification:
For each test case, first print in a line YES
if the sequence is the preorder traversal sequence of a BST or the mirror image of a BST, or NO
if not. Then if the answer is YES
, print in the next line the postorder traversal sequence of that tree. All the numbers in a line must be separated by a space, and there must be no extra space at the end of the line.
Sample Input 1:
7
8 6 5 7 10 8 11
Sample Output 1:
YES
5 7 6 8 11 10 8
Sample Input 2:
7
8 10 11 8 6 7 5
Sample Output 2:
YES
11 8 10 7 5 6 8
Sample Input 3:
7
8 6 8 5 10 9 11
Sample Output 3:
NO
二叉搜索树 (BST) 以递归方式定义为具有以下属性的二叉树: 节点的左侧子树仅包含键小于节点键的节点。节点的右侧子树仅包含键大于或等于节点键的节点。左子树和右子树也必须是二叉搜索树。如果我们交换每个节点的左右子树,那么生成的树称为BST的镜像。 现在给定一个整数键序列,您应该判断它是 BST 的先序遍历序列还是 BST 的镜像。
输入规范:每个输入文件包含一个测试用例。对于每种情况,第一行都包含一个正整数 N (≤1000)。然后在下一行给出 N 个整数键。一行中的所有数字都用空格分隔。
输出规范:对于每个测试用例,如果序列是 BST 的先序遍历序列或 BST 的镜像,则首先打印一行 YES,如果不是,则打印 NO。然后,如果答案是肯定的,请在下一行打印该树的后序遍历序列。一行中的所有数字必须用空格分隔,并且行尾不得有多余的空格。
先通过一个顺序构造树然后再写出不同的遍历序列。这是最通用的,也是最传统的解法。
最万能的方法就是先造好一棵树,然后按照一定的算法实现遍历输出。
解题过程
//构造树的方法
#include<iostream>
#include<string>
#include<map>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
vector<int>pre, temp, post;
//默认所给数据为先序,temp用来存放所造的树的先序顺序,然后比对
bool flag = false;
struct node
{
int data;
node* lchild, * rchild;
};
void insert(node*& root, int data)
{
if (root == NULL)
{
root = new node;
root->data = data;
root->lchild = root->rchild = NULL;
return;//你插入完根节点要记得返回等待接入新的节点,一直不返回就死循环了!
}
if (data < root->data)
{
insert(root->lchild, data);
}
else
{
insert(root->rchild, data);
}
}
void preorder(node* root)//根左右
{
if (root == NULL)
return;
temp.push_back(root->data);
if (flag)
{
preorder(root->rchild);
preorder(root->lchild);
}
else
{
preorder(root->lchild);
preorder(root->rchild);
}
}
void postorder(node* root)//左右根
{
if (root == NULL)
return;
if (flag)
{
postorder(root->rchild);//服气,复制粘贴的时候没有把preorder改为postorder!
postorder(root->lchild);
}
else
{
postorder(root->lchild);
postorder(root->rchild);
}
post.push_back(root->data);
}
int main()
{
int n;
cin >> n;
pre.resize(n);
node* root = NULL;
for (int i = 0; i < n; i++)
{
cin >> pre[i];
insert(root, pre[i]);
}
preorder(root);
if (temp != pre)
{
temp.clear();
flag = true;
preorder(root);
}
if (temp == pre)
{
cout << "YES" << endl;
postorder(root);
for (int i = 0; i < n; i++)
printf("%d%c", post[i], i < n - 1 ? ' ' : '\n');
}
else
{
cout << "NO"<<endl;
}
return 0;
}
解析
//根据所给的序列构建一个二叉搜索树,
//然后对这个二叉搜索树进行先序遍历,
//与遍历序列与题目所给的初始遍历比对,
// 如果相同或者是镜像,
//那么就是一个BST,否则不是。
//一些知识点:*&指针引用,可以改变引用对象的值,而*只能使用不能改变
//(注意这里的改变指实参本身,形参当然能改,只不过改不了实参而已)
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <vector>
using namespace std;
bool flag = false;
vector<int> post, pre, temp;
struct node
{
int data;//数据存放,同时也作为新的根
node* lchild, * rchild;
};
void insert(node*& root, int data)//因为我们使用指针时要插入数据,改变指针的值,所以要*&
{
if (root == NULL)//插入数据
{
root = new node;//这个是必须要写的,你写了node*root只是有了这个变量的存在,但是它还没有储存空间,
//要new它才能给它获得访问空间,他才能够有储存数据的空间
root->data = data;
root->lchild = root->rchild = NULL;
return;
}
if (data < root->data)//连接数据
insert(root->lchild, data);
else//大于等于都在右边
insert(root->rchild, data);
}
void postorder(node* root)//后序输出,左右根。
//只是调用指针指向,起到连接作用,不需要改变指针的值,所以直接*即可
{
if (root == NULL)//当前的根只要为空,就说明没有数据,代表遍历完成就返回即可
return;
if (flag)//镜像的要对应回原先镜像的顺序,如果是镜像,那么后序的左右根也就变为了右左根
{
postorder(root->rchild);
postorder(root->lchild);
}
else
{
postorder(root->lchild);
postorder(root->rchild);
}
post.push_back(root->data);//后序输出,左右根,根最后访问,所以写在最后
}
void preorder(node* root)
{
if (root == NULL)
return;
temp.push_back(root->data);//根左右,先插入根就表示先访问根
if (flag)//判断镜像
{
preorder(root->rchild);//左变右,就变为根右左
preorder(root->lchild);
}
else//判断先序
{
preorder(root->lchild);//根左右,那就一直先向左访问
preorder(root->rchild);//再就是右
}
//这里是以temp作为先序的标准,就是按照先序的方式插入,如果两者不一样就说明不是
}
int main()
{
int n;
scanf("%d", &n);
pre.resize(n);
node* root = NULL;
for (int i = 0; i < n; ++i)//即使是镜像,根节点也是一样的。所以一开始一定是根
//指针真是好用,指着就相当于连接起来了
{
scanf("%d", &pre[i]);
insert(root, pre[i]);
}
preorder(root);//首先先遍历先序,判断是否为先序
//插入完数据,建立好树之后,剩下的就是不同的方法改变指针指向,实现不同的遍历方法即可
//用的都是同一颗树,所以直接将同样的root上传遍历即可
if (temp != pre)//如果不是就看看是不是镜像
{
temp.clear();
flag = true;
preorder(root);
}
if (pre == temp)//是先序或者镜像就输出
{
postorder(root);
printf("YES\n");
for (int i = 0; i < n; ++i)
printf("%d%c", post[i], i < n - 1 ? ' ' : '\n');
//简洁最后不输出多余空格表达
}
else//都不是就NO
printf("NO\n");
return 0;
}
//根据题目条件自己造一颗树,就是左边放小的,右边大的。然后先序遍历,
//本质上可以不同就是因为如果题目给的数据不是按照先序遍历或者镜像输入的就会不同
//但是自己造的树然后按照一定的遍历顺序是一定正确的!(因为有设条件连接各个节点)
// 而题目数据是可以随便顺序的
//核心就是验证输入的数据的顺序是否为先序或者镜像。