转载https://blog.csdn.net/attitudeisaltitude/article/details/9835785
一、题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。
思路:在后续遍历得到的序列中,最后一个元素为树的根结点。从头开始扫描这个序列,比根结点小的元素都应该位于序列的左半部分;从第一个大于根结点开始到根结点前面的一个元素为止,所有元素都应该大于根结点,因为这部分元素对应的是树的右子树。根据这样的划分,把序列划分为左右两部分,我们递归地确认序列的左、右两部分是不是都是二元查找树。
例如以序列{5、7、6、9、11、10、8}为例,后序遍历结果的最后一个数字8就是根节点的值。在这个数组中,前3个数字5、7和6都比8小,是值为8的节点的左子树节点;后3个数字9,11,10都比8大,是值为8的节点的右子树节点。 我们接下来用同样的方法确定与数组每一部分对应的子树的结构。这其实就是一个递归的过程。对于序列5,7,6,最后一个数字6是左子树的根节点的值。数字5比6小,是值为6的节点的左子结点,而7则是它的右子节点。同样,在序列9,11,10中,最后一个数字10是右子树的根节点,数字9比10小,是值为10的节点的左子结点,而11则是它的右子结点。
再分析另一个序列{7,4,6,5}。后序遍历的最后一个数是根节点,因此根节点的值是5.由于第一个数字7大于5,因此在对应的二叉搜索树中,根节点上是没有左子树的,数字7,4,6都是右子树节点的值。但我们发现在右子树中有一个节点的值是4,比根节点的值5小,这违背了二叉搜索树的定义。因此不存在一颗二叉搜索树。
代码:
#include <iostream> #include <vector> #include <cstdio> using namespace std; struct Node { int data; Node *lchild, *rchild; }; vector<int> post; //检查序列post是否是二叉查找树的后序遍历序列,st与ed分别是序列的开始与结束位置 Node* Create(bool& flag, int st, int ed) { if (st > ed) return NULL; Node* root = new Node; root->data = post[ed]; int k; for (k=st; k < ed; k++) { if (post[k] > post[ed]) { break; } } for (int i = k; i < ed; i++) { if (post[i] < post[ed]) { flag = false; //return NULL; } } root->lchild = Create(flag, st, k - 1); root->rchild = Create(flag, k, ed - 1); return root; } void preTraverse(Node* root) { if (root == NULL) return; printf("%d ", root->data); preTraverse(root->lchild); preTraverse(root->rchild); } void inTraverse(Node* root) { if (root == NULL) return; inTraverse(root->lchild); printf("%d ", root->data); inTraverse(root->rchild); } void postTraverse(Node* root) { if (root == NULL) return; postTraverse(root->lchild); postTraverse(root->rchild); printf("%d ", root->data); } int main(){ int n; scanf("%d", &n); post.resize(n); for (int i = 0; i < n; i++) { scanf("%d", &post[i]); } bool flag = true; Node* root = Create(flag, 0, n - 1); if (flag) { printf("YES"); printf("\n前序遍历\n"); preTraverse(root); printf("\n中序遍历\n"); inTraverse(root); printf("\n后序遍历\n"); postTraverse(root); } else { printf("NO\n"); } return 0; }
二、题目:输入一个整数数组,判断该数组是不是某二元查找树的前序遍历的结果。如果是返回true,否则返回false。
思路:同理,在前续遍历得到的序列中,第一个元素为树的根结点。从第二个节点开始扫描这个序列,比根结点小的元素都应该位于序列的左半部分;从第一个大于根结点开始到最后一个元素为止,所有元素都应该大于跟结点,因为这部分元素对应的是树的右子树。根据这样的划分,把序列划分为左右两部分,我们递归地确认序列的左、右两部分是不是都是二元查找树。
代码:
//检查序列pre是否是二叉查找树的前序遍历序列,st与ed分别是序列的开始与结束位置 Node* Create(bool& flag, int st, int ed) { if (st > ed) return NULL; Node* root = new Node; root->data = pre[st]; int k; for (k=st+1; k <= ed; k++) { if (pre[k] > pre[st]) { break; } } for (int i = k; i <= ed; i++) { if (pre[i] < pre[st]) { flag = false; //return NULL; } } root->lchild = Create(flag, st + 1, k - 1); root->rchild = Create(flag, k, ed); return root; }