7、(★、※)判断一个序列是否是二叉查找树的后序、前序遍历序列

 转载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;

}

 

    原文作者:算法小白
    原文地址: https://www.cnblogs.com/fuqia/p/9548316.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞