二叉树操作模板

二叉树的操作模板

  • 使用递归进行遍历、查找、插入、删除、判断合法性

二叉树的遍历

先序遍历

void preorder(TreeNode* root){
	if(!root) return ;
	nums.push_back(root->val);
	preorder(root->left);
	preorder(root->right);
}

中序遍历

void inorder(TreeNode* root){
	if(!root) return ;
	inorder(root->left);
	nums.push_back(root->val);
	inorder(root->right);
}

后序遍历

void postorder(TreeNode* root){
	if(!root) return;
	postorder(root->left);
	postorder(root->right);
	nums.push_back(root->val);
}

层次遍历

  • 二叉树是无环的图,层次遍历使用BFS
  • 可以使用 BFS+ Queue 来实现,也可以使用递归来实现
class Solution {
    void levelOrder(TreeNode* node,vector<vector<int>>& res,int level){
        if(!node) return ;
        if(res.size() <= level) res.push_back({});
        res[level].push_back(node->val);
        levelOrder(node->left,res,level+1);
        levelOrder(node->right,res,level+1);
    }
    typedef pair<TreeNode*,int> Pair;
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(!root) return {};
        vector<vector<int>> res;
        levelOrder(root,res,0);
        return res;
    }
};
class Solution {
    typedef pair<TreeNode*,int> Pair;
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(!root) return {};
        vector<vector<int>> res;
        queue<Pair> vertex;
        vertex.push({root,0});
        while(vertex.size()){
            auto cur = vertex.front();
            vertex.pop();
            auto node = cur.first;
            if(!node) continue;
            if(res.size()<=cur.second) res.push_back({});
            res[cur.second].push_back(node->val);
            vertex.push({node->left,cur.second+1});
            vertex.push({node->right,cur.second+1});
        }
        return res;
    }
};

宽度遍历

  • 设节点的索引为i,则其左节点的索引为 i 2 i*2 ,右节点的索引为 i 2 + 1 i*2+1
  • 所谓宽度遍历就是在层次遍历的时候,额外携带父节点的索引信息,则可以对每层的节点进行操作
class Solution {
    vector<vector<double>> table;
    int Height(TreeNode* root){
        if(!root) return 0;
        return max(Height(root->left),Height(root->right)) + 1;
    }
    void helper(TreeNode* root,int level,double index){
        if(!root) return;
        //记录每层中最左和最右节点的索引
        if(table[level][0] == -1) table[level][0] = index;
        else{
            table[level][1] = index;
        }
        double m = index*2;
        helper(root->left,level + 1,m);
        helper(root->right,level + 1,m+1);
    }
public:
    int widthOfBinaryTree(TreeNode* root) {
        int h = Height(root);
        int size = pow(2,h);
        table = vector<vector<double>>(h,vector<double>(2,-1));
        helper(root,0,0);
        double ans = 0;
        //统计
        for(auto& it : table){
            if(it[1] == -1){
                ans = max<double>(ans,1);
            }else{
                ans = max(ans,it[1] - it[0] + 1);
            }
        }
        return ans;

    }
};
  • 可以发现,先/中/后序遍历其实就是什么时候对当前节点进行操作
  • 先序: 先记录当前节点,在遍历左子树、右子树
  • 中序: 先遍历左子树,再记录当前节点,再遍历右子树
  • 后续: 先遍历左子树,再遍历右子树,最后记录当前节点

查找给定数字是否存在二叉树中

普通的二叉树

bool isExist(TreeNode* root,int target){
	if(!root) return false;
	if(root->val == target) return true;
	return isExist(root->left,target) || isExist(root->right,target);
}

二叉搜索树

  • 使用BST的性质,搜索时候进行二分
bool isExist(TreeNode* root,int target){
	if(!root) return false;
	if(root->va == target) return true;
	else if(root->val < target)
		return isExist(root->right,target);
	else return isExist(root->left,left);
}

二叉搜索树中第K小元素


class Solution { 
	// cnt 来记录当前遍历的节点数目
    int cnt = 0;   
    //val保存第k小的结果
    int val;
    void inorder(TreeNode* root,int k){
        if(!root) return ;
        inorder(root->left,k);
        cnt++;
        if(cnt == k){
            val = root->val;
            return;
        }
        inorder(root->right,k);
    }
public:
    int kthSmallest(TreeNode* root, int k) {
        inorder(root,k);
        return val;
    }
};

BST的最小/最大值

TreeNode* Mininum(TreeNode* root){
	if(!root) return nullptr;
	if(!root->left) return root;
	return Mininum(root->left);
}
TreeNode* Maxinum(TreeNode* root){
	if(!root) return nullptr;
	if(!root->right) return root;
	return Maxinum(root->right);
}

BST 前驱/后继

TreeNode* Successor(TreeNode* root,int val){
	if(!root) return nullptr;
	auto* l = Successor(root->left,val);
	if(l) return l;
	if(root->val > val) return root;
	auto* r = Successor(root->right,val);
	if(r) return r;
	return nullptr;
}
TreeNode* Precursor(TreeNode* root,int val){
	if(!root) return nullptr;
	auto* r = Precursor(root->right,val);
	if(r) return r;
	if(root->val < val) return root;
	auto* l = Precursor(root->left,val);
	if(l) return l;
	return nullptr;
}

相同的树

  • 使用先序遍历模板
  • 如果当前节点都是null 或者值相同,则当前节点相同,继续比较左右子树节点
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(!p && !q) return true;
        if(!p || !q || p->val != q->val) return false;
        return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
    }
};

对称二叉树

class Solution {
public:
    bool ismirror(TreeNode* p,TreeNode* q){
        if(!p && !q) return true;
        if(!p || !q || p->val != q->val) return false;
        return ismirror(p->left,q->right) && ismirror(p->right,q->left);
    }
    bool isSymmetric(TreeNode* root) {
        return ismirror(root,root);
    }
};

合并二叉树

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        // 使用先序遍历框架,返回当前节点
        if(!t1 && !t2) return nullptr;
        TreeNode* root = new TreeNode(0);
        TreeNode* l1 = nullptr,*l2 = nullptr,*r1 = nullptr,*r2 = nullptr;
        if(t1){
            root->val += t1->val;
            l1 = t1->left;r1 = t1->right;
        }
        if(t2){
            root->val += t2->val;
            l2 = t2->left;r2 = t2->right;
        }
        root->left = mergeTrees(l1,l2);
        root->right = mergeTrees(r1,r2);
        return root;
    }
};

反转二叉树

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
       if(!root) return nullptr;
       auto* l = invertTree(root->left);
       root->left = invertTree(root->right);
       root->right = l;
       return root;
    }
};

判断合法性

判断是否是二叉搜索树

  • 节点的左子树只包含小于当前节点的数
  • 节点的右子树只包含大于当前节点的数
  • 所有左子树和右子树自身必须也是二叉搜索树
class Solution {
	// 携带额外信息,从上层节点传入的最大值和最小值
    bool isValidBST(TreeNode* root,TreeNode* min,TreeNode* max){
        if(!root) return true;
        
        if(min && root->val <= min->val){
            return false;
        }
        if(max && root->val >= max->val){
            return false;
        }
        return isValidBST(root->left,min,root) && isValidBST(root->right,root,max);
    }
public:
    bool isValidBST(TreeNode* root) {
        return isValidBST(root,nullptr,nullptr);
    }
};

判断是否是平衡二叉树

class Solution {
   pair<bool,int> helper(TreeNode* root){
       if(!root) return {true,-1};
       auto l = helper(root->left);
       auto r = helper(root->right);
       if(!l.first || !r.first) return {false,0};
       return make_pair(abs(l.second - r.second) <2,max(l.second,r.second)+1);
   }
public:
    bool isBalanced(TreeNode* root) {
        return helper(root).first;
    }
};

验证二叉树

class Solution {
public:
    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
        // a.不能有环,b.不能逆向,c.不能有多棵树
        //每一个节点只能有一个父节点,使用一个unordered_map来记录每个节点的信息,每次插入新节点前,先查询父节点是否存在(解决c),再查询map中是否有新节点(解决a和b)

        unordered_map<int,int> map;
        int i  = 0;
        while(i < n &&leftChild[i] == -1 && rightChild[i] == -1) i++;
        map[i] = i;
        while(i < n){
            // 该行验证父节点是否存在
            if(map.count(i) == 0) return false;
            int l = leftChild[i],r = rightChild[i];
            if(l != -1){
                //该行验证节点是否已经被使用,如果被使用过,可能会形成逆向和有环
                if(map.count(l) != 0) return false;
                map[l] = i;
            }
            if(r != -1){
                if(map.count(r) != 0) return false;
                map[r] = i;
            }
            i++;
        }
        return true;
    }
};

插入

二叉搜索树的插入操作

  • 递归插入
  • 使用后续遍历的模板,找到新值的位置插入
class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if(!root) return new TreeNode(val);
        if(root->val > val){
            root->left = insertIntoBST(root->left,val);
        }else{
            root->right = insertIntoBST(root->right,val);
        }
        return root;
    }
};
  • 非递归插入
class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        auto* node = new TreeNode(val);
        TreeNode* x=nullptr,*y = root;
        while(y){
            x = y;
            if(y->val > val) y = y->left;
            else y = y->right;
        }
        if(!x)  root = node;
        else if(x->val > val) x->left = node;
        else x->right = node;
        return root;
    }
};

BST 删除节点

  • 设要删除的节点为Z
  • 如果 Z 没有孩子节点,则直接删除Z
  • 如果Z只有一个孩子节点,用孩子节点替代Z
  • 如果Z有2个孩子节点,则需要找到Z的后继节点X和X的父节点

    用X的right节点替代X,再用X替代Z

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if(!root) return nullptr;
        //找到该节点
        if(root->val == key){
        	// 无孩子节点和只有一个孩子节点的情况
            if(!root->left) return root->right;
            if(!root->right) return root->left;
            // 2个孩子节点
            TreeNode* x = root,*y = root->right;
            // 找到后继节点和后继节点的父节点
            while(y->left){
                x = y;
                y = y->left;
            }
            // 后继节点y不是root->right节点时,需要先把y->right替代y,再把y替代root->right;
            if(x != root){
                x->left = y->right;
                y->right = root->right;
            }
            y->left = root->left;
            delete root;
            return y;
        }
        if(root->val > key)
            root->left = deleteNode(root->left,key);
        else if(root->val < key)
            root->right = deleteNode(root->right,key);
        return root;
    }
};
发布了20 篇原创文章 · 获赞 0 · 访问量 358

猜你喜欢

转载自blog.csdn.net/weixin_41964962/article/details/104823898