二叉树数常见笔试题汇总(遍历,最大深度,反向构造,共同祖先,对称判断,路经总和,序列化及反序列化操作) c++实现

1.二叉树结构体定义

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

类定义

class BinaryTree 
{
public:
    static TreeNode* head;
}

2.反序列化与序列化

2.1 反序列化

	void decode(string& str)//反序列化
    {
        if (data[0] == 'n')
        {
            head=NULL;
            return;
        }
        //切片压入容器
        vector<string> nums;
        int i = -1, j = -1;
        while (true)
        {
            i = data.find(",", i + 1);
            if (i == string::npos)
            {
                nums.push_back(data.substr(j + 1, data.size() - j));
                break;
            }
            nums.push_back(data.substr(j + 1, i - j));
            j = i;
        }
        TreeNode* root = new TreeNode(stoi(nums[0]));
        if (nums.size() == 1) 
        {
            head = root;
            return;
        }
        i = 1;//从第二个开始算起
        queue<TreeNode*> myqueue = {};
        myqueue.push(root);
        while (!myqueue.empty())
        {
            TreeNode* cur = myqueue.front();
            myqueue.pop();
            if (nums[i][0] != 'n')
            {
                cur->left = new TreeNode(stoi(nums[i]));
                myqueue.push(root->left);
            }
            if (++i == nums.size()) break;
            if (nums[i][0] != 'n')
            {
                cur->right = new TreeNode(stoi(nums[i]));
                myqueue.push(root->right);
            }
            if (++i == nums.size()) break;
        }
        head = root;
        return;
    }

2.2 序列化

 string& serialize()
    {
        vector<int> vec = {};
        if (head == NULL)
        {
            return "null";
        }
        string str = {};
        queue<TreeNode*> myqueue = {};
        myqueue.push(head);
        while (!myqueue.empty())
        {
            TreeNode* cur = myqueue.front();
            myqueue.pop();
            if (cur)
            {
                str += to_string(cur->val) + ',';
                myqueue.push(cur->left);
                myqueue.push(cur->right);
            }
            else
            {
                str += "null,";
            }
        }
        str.pop_back();
        int pos = str.find_last_of("0123456789");
        str = str.substr(0, pos + 1);
        return str;
    }

2.3 层序遍历

    void Pirnt() 
    {
        if (head == NULL) return;
        queue<TreeNode*> myqueue;
        TreeNode* cur = head;
        myqueue.push(cur);
        while (!myqueue.empty()) 
        {
            int size = myqueue.size();
            for (int i = 0; i < size; i++) 
            {
                cur = myqueue.front();
                myqueue.pop();
                cout << cur->val<<"\t";
                if (cur->left)myqueue.push(cur->left);
                if (cur->right)myqueue.push(cur->right);
            }
            cout << endl;
        }
    }

2.4 测试

#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main() 
{
	BinaryTree bt = {};
	//反序列初始化测试
	bt.decode("5,2,3,null,null,2,4,3,1");
	//按行打印
	bt.Pirnt();
	//序列化测试
	string str = bt.serialize();
	cout << str << endl;
	system("pause");
}

结果
在这里插入图片描述

3. 遍历

3.1 前序及测试

递归

    void preRecerse(TreeNode* cur = head)
    {
        if (NULL == cur) 
        {
            return;
        }
        cout << cur->val << "\t";
        preRecerse(cur->left);
        preRecerse(cur->right);
    }

迭代

    void PreTraverse() 
    {
        if (head == NULL) return;
        stack<TreeNode*> mystack;
        TreeNode* p = head;
        mystack.push(p);
        while (!mystack.empty()) {
            p = mystack.top();
            mystack.pop();
            cout << p->val << "\t";
            if (p->right) mystack.push(p->right);
            if (p->left) mystack.push(p->left);
        }
        cout << endl;
        return;
    }

测试

#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main() 
{
	BinaryTree bt = {};
	bt.decode("5,2,3,null,null,2,4,3,1");
	bt.preRecerse();
	cout << endl;
	bt.PreTraverse();
	system("pause");
}

在这里插入图片描述

3.2 中序及测试

递归

    void miRecurse(TreeNode* cur = head) 
    {
        if (NULL == cur)
        {
            return;
        }
        miRecurse(cur->left);
        cout << cur->val << "\t";
        miRecurse(cur->right);
    }

迭代

   void midTraverse() 
   {
       if (NULL == head)return;
       TreeNode* p = head;
       stack<TreeNode*> mystack;
       while (!mystack.empty() || NULL != p) 
       //如果没遍历完或者本身有数
       {
           if (NULL != p) //如果有数,那么继续往左边找
           {
               mystack.push(p);
               p = p->left;
           }
           else //如果没数了,就往上取根对根操作,取完指针指向右边
           //如果接下来右边有数,那么继续往左边取
           //如果没数了,那么再往上取,取根的根,以此类推
           {
               p = mystack.top();
               mystack.pop();
               cout << p->val << "\t";
               p = p->right;
           }
       }
   }

测试

#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main() 
{
	BinaryTree bt = {};
	bt.decode("1,2,3,null,null,4,5,6,7");
	bt.miRecurse();
	cout << endl;
	bt.midTraverse();
	system("pause");
}

在这里插入图片描述

3.3 后序及测试

递归

    void backRecurse(TreeNode* cur = head)
    {
        if (NULL == cur)
        {
            return;
        }
        backRecurse(cur->left);
        backRecurse(cur->right);
        cout << cur->val << "\t";
    }

迭代

 void backTraverse() 
 {
     vector<int> myvec;
     if (head == NULL) return;
     stack<TreeNode*> mystack;
     TreeNode* p = head;
     mystack.push(p);
     while (!mystack.empty()) {
         p = mystack.top();
         mystack.pop();
         myvec.push_back(p->val);
         if (p->right) mystack.push(p->left);
         if (p->left) mystack.push(p->right);
     }
     for (auto it = myvec.rbegin(); it != myvec.rend(); it++) 
     {
         cout << *it << "\t";
     }
     cout << endl;
 }

测试

#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main() 
{
	BinaryTree bt = {};
	bt.decode("1,2,3,null,null,4,5,6,7");
	bt.backRecurse();
	cout << endl;
	bt.backTraverse();
	system("pause");
}

在这里插入图片描述

4.反向构造

4.1 由中序和前序反向构造

    void constractByPreAndMid(vector<int>& preorder, vector<int>& inorder) 
    {
        head = myOrder(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size());
    }
private:
    TreeNode* myOrder(vector<int>& preorder, int l1, int r1, vector<int>inorder, int l2, int r2)
    {
        if (r1 < l1) return NULL;
        TreeNode* root = new TreeNode(preorder[l1]);
        int mid = l2;
        while (inorder[mid] != root->val) ++mid;
        root->left = myOrder(preorder, l1 + 1, l1 + mid - l2, inorder, l2, mid - 1);
        root->right = myOrder(preorder, l1 + mid - l2 + 1, r1, inorder, mid + 1, r2);
        return root;
    }

测试

#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main() 
{
	BinaryTree bt = {};
	vector<int> preorder = { 3,9,20,15,7 };
	vector<int> inorder = { 9,3,15,20,7 };
	bt.constractByPreAndMid(preorder, inorder);
	bt.Pirnt();
	system("pause");
}

在这里插入图片描述

4.2 由中序和后序反向构造

    void constractByPostAndMid(vector<int>& postorder, vector<int>& inorder)
    {
        head = myOrder2(postorder, 0, postorder.size() - 1, inorder, 0, inorder.size()-1);
    }
private:
    TreeNode* myOrder2(vector<int>& postorder, int l1, int r1, vector<int>inorder, int l2, int r2)
    {
        if (r1 < l1) return NULL;
        TreeNode* root = new TreeNode(postorder[r1]);
        int mid = l2;
        while (inorder[mid] != root->val) ++mid;
        root->left = myOrder2(postorder, l1, l1 + mid - l2-1, inorder, l2, mid - 1);
        root->right = myOrder2(postorder, l1 + mid - l2 , r1-1, inorder, mid + 1, r2);
        return root;
    }

测试代码

#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main() 
{
	BinaryTree bt = {};
	vector<int> preorder = { 3,9,20,15,7 };
	vector<int> inorder = { 9,3,15,20,7 };
	vector<int> postorder = { 9,15,7,20,3 };
	bt.constractByPostAndMid(postorder, inorder);
	bt.Pirnt();
	bt.constractByPreAndMid(preorder, inorder);
	bt.Pirnt();
	system("pause");
}

在这里插入图片描述

5.其他常见算法

5.1 求最大深度

    int maxDepth(TreeNode* root=head) {
        if (root == NULL)
        {
            return 0;
        }
        return max(maxDepth(root->left), maxDepth(root->right)) + 1;
    }

测试

#include"binary_tree.hpp"
TreeNode* BinaryTree::head = nullptr;
void main() 
{
	BinaryTree bt = {};
	bt.decode("1,2,3,null,null,4,5,6,7");
	bt.Pirnt();
	cout << bt.maxDepth() << endl;
	system("pause");
}

在这里插入图片描述

这里也可以用层序遍历的方式求最大值

5.3 判断是否对称

递归

    bool isSymmetric(TreeNode* root)
    {
        if (root == NULL)
        {
            return true;
        }
        return check(root->left, root->right);
    }
    
private:
    bool check(TreeNode* left, TreeNode* right)
    {
        if (left == NULL && right == NULL)
        {
            return true;
        }
        else if (left == NULL || right == NULL || left->val != right->val)
        {
            return false;
        }
        else //只剩下左右值相等,于是继续向下找
        {
            return check(left->left, right->right) && check(left->right, right->left);
        }
    }

迭代

    bool isSymmetric2(TreeNode* root)
    {
        if (root == NULL || (root->left == NULL && root->right == NULL))
        {
            return true;
        }
        queue<TreeNode*> myqueue = {};//每次都初始化为空
        myqueue.push(root->left);
        myqueue.push(root->right);
        while (!myqueue.empty())
        {
            TreeNode* aa = myqueue.front();
            myqueue.pop();
            TreeNode* bb = myqueue.front();
            myqueue.pop();
            if (aa == NULL && bb == NULL) continue;
            else if (aa == NULL || bb == NULL || aa->val != bb->val)
            {
                return false;
            }
            myqueue.push(aa->left);
            myqueue.push(bb->right);
            myqueue.push(aa->right);
            myqueue.push(bb->left);
        }
        return true;
    }

5.4 判断是否存在路径和

递归

    bool hasPathSum(int targetSum, TreeNode* root = head) {
        if (root == NULL)
        {
            return false;
        }
        else if (root->left == NULL && root->right == NULL && targetSum == root->val)
        {
            return true;
        }
        else
        {
            return hasPathSum(targetSum - root->val, root->left) || hasPathSum(targetSum - root->val, root->right);
        }
    }

迭代

    bool hasPathSum2(int targetSum,TreeNode* root = head) {
        if (root == NULL)
        {
            return false;
        }
        root->val = targetSum - root->val;
        queue<TreeNode*> q = {};
        q.push(root);
        while (!q.empty())
        {
            TreeNode* Node = q.front();
            q.pop();
            if (Node->left == NULL && Node->right == NULL && Node->val == 0)
            {
                return true;
            }
            if (Node->left)
            {
                Node->left->val = Node->val - Node->left->val;
                q.push(Node->left);
            }
            if (Node->right)
            {
                Node->right->val = Node->val - Node->right->val;
                q.push(Node->right);
            }
        }
        return false;
    }

5.5 寻找最小公共祖先

    TreeNode* lowestCommonAncestor(TreeNode* p, TreeNode* q, TreeNode* root=head) {
        if (root == NULL)
        {
            return root;//空的找个屁,既然有那肯定是根
        }
        if (root == p || root == q)
        {
            return root;//既然肯定有,而且有一个就是根,那么直接返回根,
        }
        //如果上面都不是,那么肯定在左右两边
        //根节点往下一层挪,直到根两个中一个相等为止
        TreeNode* left = lowestCommonAncestor( p, q, root->left);
        TreeNode* right = lowestCommonAncestor( p, q, root->right);
        //有三种情况,如果同在左边,那么肯定left不是空,右边为空
        //如果同在右边,那么right不是空,左边为空
        //如果两边都不为空。那么肯定是根节点
        if (left && right) return root;
        return left ? left : right;

    }
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无情の学习机器

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值