剑指offer面试题7:重建二叉树

面试题7:重建二叉树

题目:

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树,假设该输入的前序遍历和中序遍历的结果都不含有重复的数字。例如,输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并输出他的头结点。二叉树定义如下:

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) {}
 };

思路:

因为前序遍历是:中左右,中序遍历是:左中右。所以想到的是通过前序遍历先去判断每一个分支的中树,然后再根据在中序遍历的中的划分去判断左右子树,比如前序遍历最先的是1所以1就是一个根节点,然后再中序遍历中找到1把中序遍历划分为4,7,25,3,8,6,前者就为了根节点的左边子树,后着就为根节点的右边子树。

代码:

TreeNode* result(vector<int>& preorder, vector<int>& inorder){
        if(inorder.size()==0)
            return nullptr;

        int index = preorder[0];
        TreeNode* head = new TreeNode(index);
        preorder.erase(preorder.begin());

        auto item = find(inorder.begin(),inorder.end(),index);

        vector<int> inorder_left(inorder.begin(),item);
        vector<int> inorder_right(item+1,inorder.end());
        
        vector<int>preorder_left(preorder.begin(),preorder.begin()+inorder_left.size());
        vector<int>preorder_right(preorder.begin()+inorder_left.size(),preorder.end());

        head->left = result(preorder_left,inorder_left);
        head->right = result(preorder_right,inorder_right);  

        return head;
    }

考点:

  1. 考察对前序遍历和中序遍历的理解
  2. 考察分析复杂问题能力,我们把构建二叉树的大问题分解成为构建左、右子树的两个小问题。

复习三种遍历顺序:

/*--------------------------------递归实现遍历--------------------------------*/
	void X_f(TreeNode* head)
	{
		if (head == nullptr)
			return;
		cout << head->val << " ";
		X_f(head->left);

		X_f(head->right);
	}

	void Z_f(TreeNode* head)
	{
		if (head == nullptr)
			return;
		
		Z_f(head->left);
		cout << head->val << " ";
		Z_f(head->right);
	}

	void H_f(TreeNode* head)
	{
		if (head == nullptr)
			return;
		
		H_f(head->left);

		H_f(head->right);
		cout << head->val << " ";
	}

	/*--------------------------------迭代实现遍历(非递归)--------------------------------*/
	/*
	 *	先序遍历
	 *	1)先把头结点压入栈
	 *	2)从栈中弹出一个节点cur
	 *	3)打印处理cur
	 *	4)先右再左压入栈(如果有的话)
	 *	5)循环
	*/
	void  X_f_1(TreeNode* head)
	{
		cout << "先序遍历(非递归)" << endl;
		if (head != nullptr)
		{
			stack<TreeNode*>S;
			S.push(head);
			while (!S.empty())
			{
				head = S.top();
				S.pop();
				cout << head->val << " ";
				if (head->right != nullptr)
					S.push(head->right);
				if (head->left != nullptr)
					S.push(head->left);
			}
		}

	}

	void Z_f_1(TreeNode* head)
	{
		cout << "中序遍历(非递归)" << endl;
		if (head != nullptr)
		{
			stack<TreeNode*>S;
			while (!S.empty() || head != nullptr)
			{
				if (head != nullptr) {
					S.push(head);
					head = head->left;
				}	
				else{
					head = S.top();
					S.pop();
					cout << head->val << " ";
					head = head->right;
				}
			}
		}
	}

	void  H_f_1(TreeNode* head)
	{
		cout << "后序遍历(非递归)" << endl;
		if (head != nullptr)
		{
			stack<TreeNode*>S;
			stack<TreeNode*>R;
			S.push(head);
			while (!S.empty())
			{
				head = S.top();
				S.pop();
				R.push(head);
				if (head->left != nullptr)
					S.push(head->left);
				if (head->right != nullptr)
					S.push(head->right);
			}

			while (!R.empty())
			{
				head = R.top();
				R.pop();
				cout << head->val << " ";
			}
		}

	}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值