二叉树(binary tree)相关算法总结

本文总结了二叉树的相关算法,包括:求最大、最小深度,判断平衡与对称;层次、锯齿形、前中后序遍历;从遍历序列构造二叉树;验证二叉搜索树,转化有序数组;查找最近公共祖先;以及路径和问题。详细介绍了各种遍历方法的递归与迭代实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.二叉树深度,平衡,对称
2.二叉树遍历
3.构造二叉树
4.二叉搜索树
5.最近公共祖先
6.路径和

一个二叉树的节点定义为:

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

1. 二叉树深度,平衡,对称

- 求二叉树最大深度
int maxDepth(TreeNode* root)
{
	if (!root) return 0;
	return 1 + max(maxDepth(root->left), maxDepth(root->right));
}
- 求二叉树最小深度
int minDepth(TreeNode* root)
{
	if (!root) return 0;
	if (!root->left) return 1+minDepth(root->right);
	if (!root->right) return 1+minDepth(root->left);
	return 1+min(minDepth(root->left), minDepth(root->right));
}
- 判断二叉树是否平衡
bool isBalanced(TreeNode* root)
{
	if(!root) return 0;
	int left = maxDepth(root->left);
	int right = maxDepth(root->right);
	return abs(left-right) <= 1 && isBalanced(root->left) && isBalanced(root->right);
}
- 判断二叉树是否对称
bool isSymmetric(TreeNode* root) {
    if (!root)
        return true;
    return isSymmetric(root->left, root->right);
}
bool isSymmetric(TreeNode* left, TreeNode* right)
{
    if(!left || !right)
        return left==right;
    if(left->val != right->val)
        return false;
    return isSymmetric(left->left, right->right) && isSymmetric(left->right, right->left);
}

2. 二叉树遍历

二叉树遍历每个元素可通过广度优先(层次遍历,锯齿形遍历)或深度优先(前序遍历,中序遍历,后序遍历)。

- 层次遍历(level order traversal)
vector<int> levelOrderTrv(TreeNode* root)
{
	vector<int> res;
	queue<TreeNode*> qu;
	qu.push(root);
	while (!qu.empty())
	{
		TreeNode* curr = qu.front()
		res.push_back(curr->val);
		if (!curr->left) qu.push(curr->left);
		if (!curr->right) qu.push(curr->right);
		qu.pop();		
	}
	return res;
}
- 锯齿形遍历(zig-zag traversal)
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> res;
        if(!root)
            return res;
        queue<TreeNode*> q;
        q.push(root);
        bool leftToRight = true;
        while(!q.empty())
        {
            int size = q.size();
            vector<int> lev(size);
            for(int i = 0; i < size; i++)
            {
                TreeNode* node = q.front();
                q.pop();
                
                int index = leftToRight ? i : (size - 1 - i);
                
                lev[index] = node->val;
                
                if(node->left)
                    q.push(node->left);
                if(node->right)
                    q.push(node->right);
                
            }
            leftToRight = !leftToRight;
            res.push_back(lev);
            
        }
        return res;
    }
- 前序遍历(pre-order traversal)

递归法:

vector<int> preOrderTrv(TreeNode* root)
{
	vector<int> res;
	preOrder(root, res);
	return res;
}
void preOrder(TreeNode* root, vector<int> res)
{
	if (!root) return;
	res.push_back(root->val);
	preOrder(root->left);
	preOrder(root->right);
}

迭代法:

vector<int> preOrderTrv(TreeNode* root)
{
	vector<int> res;
	stack<TreeNode*> st;
	TreeNode* curr = root;
	st.push(curr);
	while (!st.empty())
	{
		curr = st.top();
		res.push_back(curr->val);
		st.pop();
		if (curr->right) st.push(curr->right);
		if (curr->left) st.push(curr->left);
	}
	return res;
}
- 中序遍历(in-order traversal)

递归法:

vector<int> inOrderTrv(TreeNode* root)
{
	vector<int> res;
	inOrder(root, res);
	return res;
}
void inOrder(TreeNode* root, vector<int> res)
{
	if (!root) return;
	res.push_back(root->val);
	inOrder(root->left);
	inOrder(root->right);
}

迭代法:

vector<int> inOrderTrv(TreeNode* root)
{
	vector<int> res;
	stack<TreeNode*> st;
	TreeNode* curr = root;
	while (!curr || !st.empty())
	{
		while (!curr)
		{
			st.push(curr);
			curr = curr->left;
		}
		curr = st.top();
		st.pop();
		res.push_back(curr->val);
		curr = curr->right;
	}
	return res;
}
- 后序遍历(post-order traversal)

递归法:

vector<int> postOrderTrv(TreeNode* root)
{
	vector<int> res;
	postOrder(root, res);
	return res;
}
void postOrder(TreeNode* root, vector<int> res)
{
	if (!root) return;
	res.push_back(root->val);
	postOrder(root->left);
	postOrder(root->right);
}

迭代法:

vector<int> postOrderTrv(TreeNode* root)
{
	vector<int> res;
	stack<TreeNode*> s1;
	stack<TreeNode*> s2;
	s1.push(root);
	while (!s1.empty())
	{
		TreeNode* curr = s1.top();
		s1.top();
		s2.push(curr);
		if (curr->left) s1.push(curr->left);
		if (curr->right) s1.push(curr->right);
	}
	while (!s2.empty())
	{
		TreeNode* node = s2.top();
		res.push_back(node->val);
		s2.pop();
	}
	return res;
}

3. 构造二叉树

- 由前序和中序遍历数组构造二叉树
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return build(preorder, 0, preorder.size()-1,
                     inorder, 0, inorder.size()-1);
    }
TreeNode* build(vector<int>& preorder, int pStart, int pEnd,
                vector<int>& inorder, int iStart, int iEnd)
{
    if(pStart > pEnd)
        return nullptr;
    TreeNode* node = new TreeNode(preorder[pStart]);
    int index;
    for(int i = iStart; i <= iEnd; i++)
    {
        if(inorder[i] == node->val)
        {
            index = i;
            break;
        }
    }
    node->left = build(preorder, pStart+1, pStart + index - iStart, inorder, iStart, index-1);
    node->right = build(preorder, pStart + index - iStart+1, pEnd, inorder, index+1, iEnd);
    return node;
}
- 由中序和后序遍历数组构造二叉树
TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
    return build(inorder, 0, inorder.size() - 1,  postorder, 0, postorder.size() - 1);
}

TreeNode* build(vector<int> &inorder, int iStart, int iEnd, vector<int> &postorder, int pStart, int pEnd){
    if(pStart > pEnd){
        return nullptr;
    }
    TreeNode* node = new TreeNode(postorder[pEnd]);
    int index;
    for(int i = iStart; i <= iEnd; i++){
        if(inorder[i] == node->val){
            index = i;
            break;
        }
    }
    node->left = build(inorder, iStart, index - 1, postorder, pStart, pStart + index - iStart - 1);
    node->right = build(inorder, index + 1, iEnd,  postorder, pEnd - iEnd + index, pEnd - 1);
    return node;
}

4. 二叉搜索树

- 验证二叉搜索树
bool isValidBST(TreeNode* root) {
        return isValidBST(root, LONG_MIN, LONG_MAX);
    }
bool isValidBST(TreeNode* root, long min, long max)
{
    if(!root)
        return true;
    if(root->val <= min || root->val >= max)
        return false;
    return isValidBST(root->left, min, root->val) && isValidBST(root->right, root->val, max);
}
- 将有序数组转化为二叉搜索树
TreeNode *sortedArrayToBST(vector<int> &num) {
        if(num.size() == 0) return NULL;
        if(num.size() == 1)
        {
            return new TreeNode(num[0]);
        }
        
        int middle = num.size()/2;
        TreeNode* root = new TreeNode(num[middle]);
        
        vector<int> leftInts(num.begin(), num.begin()+middle);
        vector<int> rightInts(num.begin()+middle+1, num.end());
        
        root->left = sortedArrayToBST(leftInts);
        root->right = sortedArrayToBST(rightInts);
        
        return root;
    }
- 二叉搜索树第K小的元素
int kthSmallest(TreeNode* root, int k) {
        stack<TreeNode*> st;
        while(true)
        {
            while(root)
            {
                st.push(root);
                root = root->left;
            }
            root = st.top();
            st.pop();
            if(--k == 0)
                return root->val;
            root = root->right;
        }
    }

5. 最近公共祖先

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    if(!root || root == p || root == q)
        return root;
    TreeNode* left = lowestCommonAncestor(root->left, p, q);
    TreeNode* right = lowestCommonAncestor(root->right, p, q);
    if(left && right)
        return root;
    return left ? left : right;
}

6. 路径和

- 是否有一和为给定值的根-节点路径
bool hasPathSum(TreeNode* root, int sum) {
        if(!root)
            return false;
        if(root->val == sum && !root->left && !root->right)
            return true;
        return hasPathSum(root->left, sum - root->val) ||
               hasPathSum(root->right, sum - root->val);
    }
- 找出所有和为给定值的根-节点路径
vector<vector<int>> pathSum(TreeNode* root, int sum) {
        vector<vector<int>> paths;
        vector<int> path;
        findPaths(root, sum, path, paths);
        return paths;
    }
    void findPaths(TreeNode* root, int sum, vector<int> &path, vector<vector<int>> &paths)
    {
        if (!root) return;
        
        path.push_back(root->val);
        
        if (!(root->left) && !(root->right) && sum == root->val)
            paths.push_back(path);
        
        findPaths(root->left, sum-root->val, path, paths);
        findPaths(root->right, sum-root->val, path, paths);
        
        path.pop_back();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值