二叉树操作模板

二叉树的操作模板

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

二叉树的遍历

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

递归版本:

vector<int> preorder(TreeNode* root){
	vector<int> result;
	stack<TreeNode*> st;
	TreeNode* node = root;
	while(node || !st.empty()){
		while(node){
			st.push(node);
			result.push_back(node->val);
			node = node->left;
		}
		if(!st.empty()){
			auto t = st.top();
			st.pop();
			node = t->right;
		}
	}
	return result;
}
中序遍历
void inorder(TreeNode* root){
	if(!root) return ;
	inorder(root->left);
	nums.push_back(root->val);
	inorder(root->right);
}

递归版本:

vector<int> preorder(TreeNode* root){
	vector<int> result;
	stack<TreeNode*> st;
	TreeNode* node = root;
	while(node || !st.empty()){
		while(node){
			st.push(node);
			node = node->left;
		}
		if(!st.empty()){
			auto t = st.top();
			st.pop();
			result.push_back(node->val);
			node = t->right;
		}
	}
	return result;
}
后序遍历
void postorder(TreeNode* root){
	if(!root) return;
	postorder(root->left);
	postorder(root->right);
	nums.push_back(root->val);
}

递归版本:

vector<int> postorderTraversal(TreeNode* root) {
 	vector<int> result;
    stack<pair<TreeNode*,int>> st;
    TreeNode* node = root;
    if(!root) return result;
    while(node || !st.empty()){
        while(node){
            st.push(make_pair(node,1));
            node = node->left;
        }
        if(!st.empty()){
            auto& t = st.top();
            auto n = t.first;
            if(t.second == 0){
                st.pop();
                result.push_back(n->val);
            }else{
                if(n->right)
                    node = n->right;
                t.second = 0;
            }
        }
    }
    return result;
}
层次遍历
  • 二叉树是无环的图,层次遍历使用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 i2,右节点的索引为 i ∗ 2 + 1 i*2+1 i2+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 {
    int depth(TreeNode* root){
        if(!root) return 0;
        int l = depth(root->left);
        if(l < 0) return -1;
        int r = depth(root->right);
        if(r < 0) return -1;
        if(abs(l-r) > 1) return -1;
        return max(l,r) + 1;
    }
public:
    bool isBalanced(TreeNode* root) {
        return depth(root) != -1;
        
    }
};
验证二叉树
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;
    }
};

二叉树剪枝

分析
  • 要求: 返回移除了所有不包含 1 的子树的原二叉树
  • 重点在于删除 所有不包含1的子树
  • 不包含1的子树:所有节点都是0,
  • 那么从叶子节点开始往上走,只要节点值为0且该节点无左右节点,则本节点需要删除。
  • 总体查找的时候需要按照后序遍历思路
class Solution {
public:
    TreeNode* pruneTree(TreeNode* root) {
        if(!root) return nullptr;
        root->left = pruneTree(root->left);
        root->right = pruneTree(root->right);
        if(root->val == 0 && !root->left && ! root->right)
            return nullptr;
        else return root;
    }
};

一个比较完整的BST 类

  • BST.hxx
#pragma once 
#include <vector>
#include <string>
#include <stdexcept>

struct TreeNode{
    int val;
    TreeNode* left = nullptr;
    TreeNode* right = nullptr;
    TreeNode(int v):val(v){}
};

class BST{
private:
    TreeNode* root = nullptr;
    TreeNode* DeleteTree(TreeNode* node);
    void InsertNode(TreeNode* node);
    TreeNode* SearchNode(int v);
    void Depth(TreeNode* r,int&depth,int temp);
    int Depth(TreeNode* r);
    TreeNode* MaxNode(TreeNode* r){
        if(!r) return nullptr;
        while(r->right)
            r = r->right;
        return r;
    }
    TreeNode* MaxNode(){
        return MaxNode(root);
    }
    TreeNode* MinNode(TreeNode* r){
        if(!r) return nullptr;
        while(r->left)
            r = r->left;
        return r;
    }
    TreeNode* MinNode(){
        return MinNode(root);
    }
    void PreOrder(TreeNode* r,std::vector<int>& res);
    void InOrder(TreeNode* r,std::vector<int>& res);
    void PostOrder(TreeNode* r,std::vector<int>& res);
    
public:
    BST(){}
    ~BST(){
        DeleteTree(root);
    }
    void Put(int v){
        TreeNode* node = new TreeNode(v);
        InsertNode(node);
    }
    TreeNode* Get(int v){
        return SearchNode(v);
    }
    // 递归操作
    void PreOrder(std::vector<int>& res);
    void InOrder(std::vector<int>& res);
    void PostOrder(std::vector<int>& res);
    // 非递归
    std::vector<int> PreOrder();
    std::vector<int> InOrder();
    std::vector<int> PostOrder();
    std::vector<std::vector<int>> LevelOrder();
    TreeNode* DeleteNode(int v);
    TreeNode* Successor(int v);
    TreeNode* Predecessor(int v);
    int MaxVal(){
        TreeNode* m = MaxNode();
        if(!m){
            throw std::runtime_error("bst is empty");
        }
        return m->val;
    }
    int MinVal(){
        TreeNode* m = MinNode();
        if(!m)
            throw std::runtime_error("bst is empty");
        return m->val;
    }
    int Depth(){
        if(!root)
            return 0;
        return Depth(root);
    }
};
  • BST.cpp
#include "BST.hxx"
#include <stack>
#include <queue>
#include <utility>
#include <cmath>
#include <unordered_map>

TreeNode* BST::DeleteTree(TreeNode* node){
    if(!node){
        return nullptr; 
    }
    DeleteTree(node->left);
    DeleteTree(node->right);
    delete node;
    return nullptr;
}
void BST::InsertNode(TreeNode* node){
    TreeNode* r = root;
    TreeNode* p = nullptr;
    while(r){
        p = r;
        if(r->val < node->val){
            r = r ->right;
        }else if(r->val > node->val){
            r = r->left;
        }else{
            return;
        }
    }
    if(!p){
        root = node;
        return;
    }
    if(p->val < node->val)
        p->right = node;
    else
        p->left = node;  
}
TreeNode* BST::SearchNode(int v){
    if(!root){
        return nullptr;
    }
    TreeNode* r = root;
    while(r){
        if(r->val == v)
            return r;
        else if(r->val > v)
            r = r->left;
        else 
            r = r->right;
    }
    return nullptr;
}
// DFS 
void BST::Depth(TreeNode*r,int&depth,int temp){
    if(!r){
        depth = std::max(depth,temp);
        return;
    }
    Depth(r->left,depth,temp+1);
    Depth(r->right,depth,temp+1);
}
int BST::Depth(TreeNode* r){
    if(!r)
        return 0;
    int  depth = 1;
    Depth(r,depth,0);
    return depth;
}
TreeNode* BST::Predecessor(int v){
    // 1. find v node
    // 2. if v node has left node,then the predecessor
    // is the max node of left subtree of the v node
    // 3. otherwise, the predecessor must be its ancestor node,
    // which is the right node of parent
    
    std::unordered_map<TreeNode*,TreeNode*> path;
    TreeNode* r = root;
    TreeNode* p = nullptr;
    while(r){
        path[r] = p;
        if(r->val == v){
            break;
        }
        p = r;
        if (r->val < v){
            r = r->right;
        }else {
            r = r->left;
        }
    }
    TreeNode* vnode = r;
    // not find v node;
    if(!vnode){
        return nullptr;
    }
    if(vnode->left){
        return MaxNode(vnode->left);
    }
    while(p && p->left == vnode){
        vnode = p;
        p = path[vnode];
    }
    return p ? p : nullptr;
}
TreeNode* BST::Successor(int v){
    /**
     * 1. find vnode
     * 2. if vnode has right node,the successor is the min node of its right subtree
     * 3. otherwise,the successor must be its ancestor,which is the left node of its parent
    */
    TreeNode* r = root;
    TreeNode* p = nullptr;
    std::unordered_map<TreeNode*,TreeNode*> path;
    while(r){
        path[r] = p;
        if(r->val == v)
                break;
            p = r;
            if(r->val < v){
                r = r->right;
            }else
            {
                r = r->left;
            }
    }
    TreeNode* vnode = r;
    if(!vnode)
        return nullptr;
    if(vnode->right)
        return MinNode(vnode->right);
    
    while(p && p->right == vnode){
        vnode = p;
        p = path[vnode];
    }
    return p ? p : nullptr;
}

TreeNode* BST::DeleteNode(int v){
    /**
     * 1. find v node
     * 2. if v node is leaf, set left or right of its parent is nullptr
     * 3. if v node only has left node , let its left node replace vnode
     * 4. if v node only has right node, find minnode of its right subtree, 
     *    let minnode replace vnode
     * 5. if v node has left and right node, find minnode of its right subtree,
     *    let minnode replace vnode
     * 
    */
    if(!root) return nullptr;
    TreeNode* r  = root;
    TreeNode* p = nullptr;
    TreeNode* pp = nullptr;
    while(r){
        if(r->val == v)
            break;
        pp = p;
        p = r;
        if(r->val < v)
            r = r->right;
        else 
            r = r->left;    
    }
    // if vnode is root,its parent node is nullptr
    if(!p){
        root = nullptr;
        return r;
    }
    TreeNode* vnode = p;
    TreeNode** pp_child = pp->left == vnode ? &(pp->left) : &(pp->right);
	// 1 and 2 case
    if(!vnode->right){
        *pp_child = vnode->left;
        return vnode;
    }
    TreeNode* minnode = vnode->right;
    while(minnode->left){
        p = minnode;
        minnode = minnode->left;
    }
    if(p != vnode){
        p->left = minnode->right;
        minnode->right = vnode->right;
    }
    minnode->left = vnode->left;
    vnode->left = nullptr;
    vnode->right = nullptr;
    *pp_child = minnode;
    return vnode;
}
void BST::PreOrder(TreeNode* r,std::vector<int>& res){
    if(!r) return;
    res.push_back(r->val);
    PreOrder(r->left,res);
    PreOrder(r->right,res);
}
void BST::PreOrder(std::vector<int>& res){
    if(!root) return;
    res.push_back(root->val);
    PreOrder(root->left,res);
    PreOrder(root->right,res);
}
std::vector<int> BST::PreOrder(){
    std::vector<int> res;
    std::stack<TreeNode*> stack;
    TreeNode* r = root;
    while(r || !stack.empty() ){
        while(r){
            res.push_back(r->val);
            stack.push(r);
            r = r->left;
        }
        if(!stack.empty()){
            auto n = stack.top();
            stack.pop();
            r = n->right;
        }
    }
    return res;
}

void BST::InOrder(TreeNode* r,std::vector<int>& res){
    if(!r) return;
    InOrder(r->left,res);
    res.push_back(r->val);
    InOrder(r->right,res);
}
void BST::InOrder(std::vector<int>& res){
    if(!root) return;
    InOrder(root->left,res);
    res.push_back(root->val);
    InOrder(root->right,res);
}
std::vector<int> BST::InOrder(){
    std::vector<int> res;
    std::stack<TreeNode*> stack;
    TreeNode* r = root;
    while(r || !stack.empty() ){
        while(r){
            stack.push(r);
            r = r->left;
        }
        if(!stack.empty()){
            auto n = stack.top();
            stack.pop();
            res.push_back(n->val);
            r = n->right;
        }
    }
    return res;
}
void BST::PostOrder(TreeNode* r,std::vector<int>& res){
    if(!r) return;
    PostOrder(r->left,res);
    PostOrder(r->right,res);
    res.push_back(r->val);
}
void BST::PostOrder(std::vector<int>& res){
    if(!root) return;
    PostOrder(root->left,res);
    PostOrder(root->right,res);
    res.push_back(root->val);
}
std::vector<int> BST::PostOrder(){
    std::vector<int> res;
    std::stack<std::pair<TreeNode*,bool>> stack;
    TreeNode* r = root;
    while(r || !stack.empty() ){
        while(r){
            stack.push(std::make_pair(r,false));
            r = r->left;
        }
        if(!stack.empty()){
            auto& n = stack.top();
            if(n.second || !n.first->right){
                stack.pop();
                res.push_back(n.first->val);
            }else{
                n.second = true;
                r =  n.first->right;
            }
        }
    }
    return res;
}
std::vector<std::vector<int>> BST::LevelOrder(){
    std::vector<std::vector<int>>  res;
    if(!root)return res;
    std::queue<std::pair<TreeNode*,int>> que;
    que.push(std::make_pair(root,0));
    std::vector<int> one_level;
    int last = 0;
    while(!que.empty()){
        auto& node = que.front();
        if(node.second != last){
            res.emplace_back(std::move(one_level));
            last = node.second;
        }
        one_level.push_back(node.first->val);
        if(node.first->left)
            que.push(std::make_pair(node.first->left,node.second+1));
        if(node.first->right)
            que.push(std::make_pair(node.first->right,node.second+1));
        que.pop();
    }
    res.emplace_back(std::move(one_level));
    return res;        
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值