二叉搜索树的遍历

二叉搜索树的操作

  • 定义
  • 验证二叉搜索树
    • 思路1
    • 思路2
  • 二叉搜索树查找
  • 二叉搜索树插入
  • 二叉搜索树删除
    • 思路1
    • 思路2:递归实现
  • 平衡二叉树
    • 思路1:递归实现
    • 思路2
  • 有序数组转换为二叉搜索树
  • N叉树
    • N叉树前序遍历
      • 思路1:递归实现
      • 思路2:迭代实现
    • N叉树后序遍历
      • 思路1:递归实现
    • 思路2:迭代实现
    • N叉树最大深度

定义

  • 二叉搜索树(BST)是二叉树的一种特殊表示形式,它满足如下特性:
    • 每个节点中的值必须大于(或等于)存储在其左侧子树中的任何值。
    • 每个节点中的值必须小于(或等于)存储在其右子树中的任何值。

验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

思路1

	//思路1:递归  不仅要保证左子节点小于等于根节点,右子节点大于等于根节点,还要保证整个右子树的元素都应该大于根节点
    //    即要保存上下界
    bool isValidBST(TreeNode* root) {
        return helper(root,__LONG_MAX__,__LONG_MAX__); //设置为null时,当成0,对于0会出错,还有卡边界问题,恶心
    }
    bool helper(TreeNode* root,long low,long upper){
        if(root == nullptr){return true;}
        if(low != __LONG_MAX__ && root->val <= low){return false;} //比下界还小,不符合二叉搜索树规则
        if(upper != __LONG_MAX__ && root->val >= upper){return false;}

        if(!helper(root->left,low,root->val)){return false;}//判断左子树是否是二叉搜索树,最大界限是根节点
        if(!helper(root->right,root->val,upper)){return false;}
        return true;
    }

思路2

	//思路2:通过中序遍历,比较是从小到大排列的
    bool isValidBST(TreeNode* root){
        if(root == nullptr){return true;}
        vector<int> temp;
        stack<TreeNode*> visit;
        long min = -__LONG_MAX__;   //真无语,卡边界值
        while(root != nullptr || !visit.empty()){
            if(root != nullptr){
                visit.push(root);
                root = root->left;
            }
            else{
                root = visit.top(); //每次弹出的就是最左的值,最小
                visit.pop();
                if(root->val <= min){//使用min记录上一个值,可以不用保存中序遍历数组
                    return false;//比上个小,则不满足二叉搜索树规则
                }
                min = root->val;
                root = root->right;
            }
        }
        return true;
    }

二叉搜索树查找

给定二叉搜索树(BST)的根节点和一个值。 你需要在BST中找到节点值等于给定值的节点。 返回以该节点为根的子树。 如果节点不存在,则返回 NULL。

	//思路:比较root节点值和给定查找的val大小,相等返回即可,小于则去右子树查找,大于去左子树找,直到为空说明不存在
    TreeNode* searchBST(TreeNode* root, int val) {
        if(root == nullptr){return NULL;}
        while(root != nullptr){
            if(root->val == val){
                return root;
            }
            else if(root->val < val){
                root = root->right;
            }
            else{
                root = root->left;
            }
        }
        return NULL;
    }

二叉搜索树插入

给定二叉搜索树(BST)的根节点和要插入树中的值将值插入二叉搜索树。返回插入后二叉搜索树的根节点。保证原始二叉搜索树中不存在新值。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。

	//思路:一种使整体操作变化最小的经典方法。思想是为目标节点找出合适的叶节点位置,然后将该节点作为叶节点插入
    // 1、根据节点值与目标节点值的关系,搜索左子树或右子树;
    // 2、重复步骤 1 直到到达外部节点;
    // 3、根据节点的值与目标节点的值的关系,将新节点添加为其左侧或右侧的子节点。
    // TreeNode* insertIntoBST(TreeNode* root, int val) {
    //     TreeNode* cur = root;
    //     TreeNode* temp;
    //     while(cur != nullptr){
    //         temp = cur;
    //         if(cur->val < val){
    //             cur = cur->right;
    //         }
    //         else if(cur->val > val){
    //             cur = cur->left;
    //         }
    //     }
    //     if(temp->val < val){temp->right = new TreeNode(val);}
    //     else{temp->left = new TreeNode(val);}
    //     return root;
    // }
    //仍旧是上面思路,不过使用递归实现
    TreeNode* insertIntoBST(TreeNode* root, int val){
        if(root == nullptr){return new TreeNode(val);}
        else{
            helper(root,val);
        }
        return root;
    }
    void helper(TreeNode* root,int val){
        if(root->val < val){//root节点比val 小,要插入右子树
            if(root->right == nullptr){//右子节点为空,到达叶子节点
                root->right = new TreeNode(val);
            }
            else{
                helper(root->right,val);
            }
        }
        else{
            if(root->left == nullptr){
                root->left = new TreeNode(val);
            }
            else{
                helper(root->left,val);
            }
        }
    }

二叉搜索树删除

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

  • 一般来说,删除节点可分为两个步骤:
    • 首先找到需要删除的节点;
    • 如果找到了,删除它。

思路1

	//思路:使整体操作变化最小的方法。用一个合适的子节点来替换删除的目标节点。根据子节点个数,需考虑以下三种情况:
    // 1. 如果目标节点没有子节点,我们可以直接移除该目标节点。
    // 2. 如果目标节只有一个子节点,我们可以用其子节点作为替换。
    // 3. 如果目标节点有两个子节点,需在右子树找到最小值,然后将该最小值赋值给root,再删除该最小值。
    //      另一种方法,找到最小值节点,将最小值节点指向当前节点左孩子,即当前节点左子树放到最小值左子树
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (!root) return nullptr;
        TreeNode *cur = root, *pre = nullptr;//记录上一个节点 因为需要知道
        while (cur != nullptr) {//首先找到要删除的key
            if (cur->val == key) break;
            pre = cur;
            if (cur->val > key) cur = cur->left;
            else cur = cur->right;
        }
        if (!pre) return del(cur); //pre为空,说明删除的是根节点
        if (pre->left && pre->left->val == key) pre->left = del(cur);//加上pre->left!=null 是防止出现没找到删除元素
        else pre->right = del(cur);
        return root;
    }
    TreeNode* del(TreeNode* node) {
        if (node == nullptr) return nullptr;
        if (node->right == nullptr) return node->left;
        //左右都有节点,该方法则找到最小值节点,将最小值节点指向当前节点左孩子,即当前节点左子树放到最小值左子树
        TreeNode *t = node->right;
        while (t->left != nullptr) t = t->left;
        t->left = node->left;
        return node->right;//返回node->right,并且要删除的放到最小的左子树了,则把该node删了
    }

思路2:递归实现

	//递归实现
    TreeNode* deleteNode(TreeNode* root, int key){
        if(root == nullptr){return nullptr;}
        if(root->val < key){
            root->right = deleteNode(root->right,key); //递归删除以root->right为根的右子树
        }
        else if(root->val > key){
            root->left = deleteNode(root->left,key);
        }
        else{ // root->val = key   find
            if(root->left == nullptr){root = root->right;}
            else if(root->right == nullptr){root = root->left;}
            else{
                TreeNode* cur = root->right; //找到右子树最小值
                while(cur->left != nullptr){cur = cur->left;}
                root->val = cur->val;
                root->right = deleteNode(root->right,cur->val);//递归删除右子树中那个最小值cur->val
            }
        }
        return root;
    }

平衡二叉树

一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1。

思路1:递归实现

	//思路1:高度平衡的二叉树,其左右两个子树的高度差的绝对值不超过1,可以递归实现
    bool isBalanced(TreeNode* root) {
        if(root == nullptr){return true;}
        if(abs(maxDepth(root->left) - maxDepth(root->right)) > 1){
            return false;
        }
        return isBalanced(root->left) && isBalanced(root->right);
    }
    //计算一个节点子树的最大深度
    int maxDepth(TreeNode* root){
        if(root == nullptr){return 0;}
        return (1 + max(maxDepth(root->left),maxDepth(root->right)));
    }

思路2

	//思路2:上面的方法会重复计算树的高度,从低向上记录每个节点的高度,同时比较,要大于2则返回false
    bool res = true;
    bool isBalanced(TreeNode* root) {
        if(root == nullptr){return true;}
        helper(root);
        return res;
    }
    int helper(TreeNode* root){
        if(root == nullptr){return 0;}
        int left = helper(root->left) + 1;
        int right = helper(root->right) + 1;
        if(abs(left - right) > 1){res = false;}
        return max(left,right);
    }

有序数组转换为二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

	//思路:因为是升序排列,那么中间可以看成根,左侧都小于根,右侧都大于根,左右子树按同样方法递归构造
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        TreeNode* root = helper(nums,0,nums.size()-1);
        return root;
    }
    TreeNode* helper(vector<int>& nums,int l,int r){
        if(l > r){return nullptr;}
        int m = (r + l) / 2;
        TreeNode* root = new TreeNode(nums[m]);
        root->left = helper(nums,l,m-1);
        root->right = helper(nums,m+1,r);
        return root;
    }

N叉树

class Node {
public:
    int val;
    vector<Node*> children;
    Node() {}
    Node(int _val) {
        val = _val;
    }
    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};

N叉树前序遍历

思路1:递归实现

	//思路1:递归实现,先加入根节点,之后从左到右递归每个孩子
    vector<int> preorder(Node* root) {
        vector<int> res;
        helper(res,root);
        return res;
    }
    void helper(vector<int>& res,Node* root){
        if(root == nullptr){return;}
        res.push_back(root->val);
        for(int i = 0; i < root->children.size(); ++i){
            helper(res,root->children[i]);
        }
    }

思路2:迭代实现

	//思路2:迭代实现  关键有一点是有多个孩子,因为前序遍历顺序是根左右,且使用stack保存,
	//  为了能够先访问左孩子可以逆序将children放入栈中
    vector<int> preorder(Node* root){
        vector<int> res;
        if(root == nullptr){return res;}
        stack<Node*> visit;
        visit.push(root);
        while(!visit.empty()){
            root = visit.top();
            visit.pop();
            res.push_back(root->val);//得到当前根节点值
            for(int i = root->children.size() - 1; i >= 0; --i){
                visit.push(root->children[i]);
            }
        }
        return res;
    }

N叉树后序遍历

思路1:递归实现

	vector<int> postorder(Node* root) {
        vector<int> res;
        helper(res,root);
        return res;
    }
    void helper(vector<int>& res,Node* root){
        if(root == nullptr){return;}
        for(int i = 0; i < root->children.size(); ++i){
            helper(res,root->children[i]);
        }
        res.push_back(root->val);
    }

思路2:迭代实现

	//思路2:迭代实现  修改前序遍历代码,将遍历左右子树的顺序对调,
    //   即可用栈保存一个根节点->右子树->左子树的遍历序列,然后反序输出即可
    vector<int> postorder(Node* root){
        vector<int> res;
        if(root == nullptr){return res;}
        stack<Node*> temp;
        temp.push(root);
        while(!temp.empty()){
            root = temp.top();
            temp.pop();
            res.push_back(root->val);
            for(int i = 0; i < root->children.size(); ++i){ //从左到右入栈,修改前序遍历代码
                temp.push(root->children[i]);
            }
        }
        int len = res.size();
        int mid = len / 2;
        for(int i = 0; i < mid; ++i){//逆序一下,就是后序遍历结果
            int n = res[i];
            res[i] = res[len - i - 1];
            res[len -i -1] = n;
        }
        return res;
    }

N叉树最大深度

最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。

	int maxDepth(Node* root) {
        if(root == nullptr){return 0;}
        int _max = 0;
        for(int i = 0; i < root->children.size(); ++i){
            int temp = maxDepth(root->children[i]);
            _max = _max > temp ? _max : temp;
        }
        return 1 + _max;
    }

你可能感兴趣的:(LeetCode,二叉树,数据结构,面试,二叉搜索树,c++,二叉链表,插入,删除)