打印普通二叉树最大搜索子树

本文介绍了一种算法,用于在任意二叉树中找到符合二叉搜索树性质、节点数量最多的子树。通过递归后序遍历,利用二叉搜索树的特性进行节点计数,并记录最大的搜索子树。

点:二叉树边界技巧


题意:一个任意的二叉树,可以不是二叉排序树,或者部分子树是二叉排序的,打印这个二叉树中符合二叉搜索树性质的子树中,节点最多的子树

程序员代码面试指南面试题


思路:二叉排序树的性质就是:父节点比左节点大,比右节点小。依赖这个性质思考:

首先,这个适合后续遍历,因为后续遍历能得到左右子树的执行结果再去判断计算自己的结果,


然后,随便画一个二叉树

1、每个符合二叉排序性质的子树的节点个数,等于左子树个数加上右子树个数加上1(自己),这便于整体统一遍历计算

2、对于叶子节点,可以认为这种单节点也是一个子树,且节点个数是左节点个数0加上右节点个数0加上1,等于1

3、非叶子节点都这样类推,如果发现不符合二叉排序性质,返回1


同时,入栈一个最大值的标志变量和一个最大搜索子树根节点变量随递归入栈,当发现某节点的节点数超限时更新这个变量,更重要的是要更新最大搜索子树的根节点为当前节点,这样递归结束后就会得到最大搜索子树的根节点。

代码实现禁掉了根节点作为最大搜索子树的根节点,注意这个是个trick。


代码:

#include <iostream>
#include <queue>


template<class T> struct Node {
    Node<T> *left;
    Node<T> *right;
    T val;
    Node(T _val):val(_val), left(nullptr), right(nullptr){}
};

template<class T> class Btree {
    Node<T> *root;

public:
    Btree():root(nullptr) {}
    void Free (Node<T> *cur) {
        if (cur) {
            Free(cur->left);
            Free(cur->right);
            delete cur;
            cur = nullptr;
        }
    }
    ~Btree() {
        Free(root);
    }

    void Add (T val) {
        if (!root) {
            root = new Node<T>(val);
            return;
        }
        
        Node<T> *cur = root;
        while (cur) {
            if (cur->val > val) {
                if (!cur->left) {
                    Node<T> *newnode = new Node<T>(val);
                    cur->left = newnode;
                    break;
                } else {
                    cur = cur->left;
                }
            } else if (cur->val < val) {
                if (!cur->right) {
                    Node<T> *newnode = new Node<T>(val);
                    cur->right = newnode;
                    break;
                } else {
                    cur = cur->right;
                }
            } else {
                break;
            }
        }
    }

    void Update (T val, T newval) {
        if (root) {
            Node<T> *cur = root;
            while (cur) {
                if (cur->val > val) {
                    if (cur->left) {
                        cur = cur->left;
                    } else {
                        break;
                    }
                } else if (cur->val < val) {
                    if (cur->right) {
                        cur = cur->right;
                    } else {
                        break;
                    }
                } else {
                    cur->val = newval;
                    break;
                }
            }
        }
    }

    void level_traverse (Node<T> *subroot) {
        if (!subroot) {
            return;
        }
        std::queue<Node<T> *> q1, q2;
        q1.push(subroot);

        while (!q1.empty()) {
            while (!q1.empty()) {
                std::cout << q1.front()->val << "\t";
                if (q1.front()->left) {
                    q2.push(q1.front()->left);
                }
                if (q1.front()->right) {
                    q2.push(q1.front()->right);
                }
                q1.pop();
            }
            while (!q2.empty()) {
                q1.push(q2.front());
                q2.pop();
            }
            std::cout << std::endl;
        }
    }

    int FindBiggestSearchSubtree (Node<T> *cur, int &max, Node<T> *&subroot) {
        if (cur) {
            int cnt_l = FindBiggestSearchSubtree(cur->left, max, subroot);
            int cnt_r = FindBiggestSearchSubtree(cur->right, max, subroot);
            

            int res;
            if (((cur->left && cur->val <= cur->left->val) ||
                 (cur->right && cur->val >= cur->right->val))) {
                res = 1;
            } else {
                res = cnt_l + cnt_r + 1;
            }
            if (max < res) {
                max = res;
                if (cur != root) {
                    subroot = cur;
                }
            }
            return res;
        } else {
            return 0;
        }
    }
    
    void FindBiggestSearchSubtree () {
        int max = 1;
        Node<T> *subroot = root;
        FindBiggestSearchSubtree(root, max, subroot);
        level_traverse(subroot);
    }
};

int main () {
    Btree<int> bt;
    bt.Add(10);
    bt.Add(7);
    bt.Add(12);
    bt.Add(5);
    bt.Add(9);
    bt.Add(11);
    bt.Add(20);
    bt.Add(0);
    bt.Add(6);
    bt.Add(8);
    bt.Add(15);
    bt.Add(25);
    bt.Add(14);
    bt.Add(18);
    bt.Add(22);
    bt.Add(28);

    bt.Update(11, 111);
    bt.FindBiggestSearchSubtree();
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值