剑指offer-二叉树

【04 重建二叉树】

题目描述

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

思路:

1) 二叉树的构建,赋值,左右子树的便利?
2) 由前序列表,中序列表 恢复左右子树:  前序的根,在中序中划分左右子树,递归重构左右子树
3) C++ 读取未知长度的数组,以回车判断数组结束

样例:

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(int x) : val(x), left(NULL), right(NULL) {}
};

TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {	
//根据前序列表和中序列表,重构二叉树。前序的第一个元素为树的根 可以在中序列表划分出 左右子树 
    if(pre.empty()||vin.empty())
		return NULL;
	if(pre.size()!=vin.size())
		return NULL;
		
	TreeNode *p;
 	p = (TreeNode*)malloc(sizeof(TreeNode));
    int i=0,mid=0;
    for(i=0;i<vin.size();i++)
    {
    	if(pre[0]==vin[i])
    		mid=i;
	}
	vector<int> pre_left,pre_right,vin_left,vin_right;
	for(i=0;i<mid;i++)
	{
		pre_left.push_back(pre[i+1]);
		vin_left.push_back(vin[i]);
	}
	for(i=mid+1;i<vin.size();i++)
	{
		pre_right.push_back(pre[i]);
		vin_right.push_back(vin[i]);
	}
    p->val = pre[0];
    p->left = reConstructBinaryTree(pre_left,vin_left);
    p->right = reConstructBinaryTree(pre_right,vin_right);
	return p;
}

【17 树的子结构】

题目描述

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路:

1) 首先判断,递归判断A和B是否是同一棵树;否则判断左子树或右子树 与 B是否为同一棵树
2) 递归判断 两棵树是否为同一颗树:判断 的各个节点是否都相同


bool SameTree(TreeNode* pRoot1, TreeNode* pRoot2)    // 递归判断 两棵树的元素是否都相同 
{
	bool val;
	if(pRoot2==NULL)
		return true;
	if(pRoot1==NULL)
		return false;
	if(pRoot1->val!=pRoot2->val)
		return false;
	else
		return SameTree(pRoot1->left,pRoot2->left) && SameTree(pRoot1->right,pRoot2->right);
}
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)  // 递归判断	二叉树 2 是不是二叉树1 的子结构
{
	bool val = false;
	if(pRoot1==NULL ||pRoot2==NULL)
		return val;
	return SameTree(pRoot1,pRoot2) | HasSubtree(pRoot1->left,pRoot2) || HasSubtree(pRoot1->right,pRoot2);
}

【18 二叉树的镜像】

题目描述

操作给定的二叉树,将其变换为源二叉树的镜像。

输入描述:

二叉树的镜像定义:源二叉树 
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	镜像二叉树
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5

思路:

1) 递归翻转 左右子树
2)非递归翻转, 利用堆存放在 节点

void Mirror(TreeNode *pRoot)		//递归实现 翻转 二叉树 
{
	TreeNode *p; 
	if(pRoot==NULL)
	{
		return;
	}
	else{
		p= pRoot->left;
		pRoot->left = pRoot->right;
		pRoot->right = p;
		Mirror(pRoot->left);
		Mirror(pRoot->right);
		//cout<<pRoot->left->val<<','<<pRoot->right->val<<endl; 
	}	
}

//非递归实现
void Mirror_non(TreeNode *pRoot)
{
	if(pRoot==NULL)
		return;
	stack<TreeNode*> s;			//栈 用来保存 节点。我们还需要翻转左右子树 
	s.push(pRoot);
	while(!s.empty())
	{
		TreeNode *p = s.top();				
		cout<<s.size()<<','<<p->val<<endl;
		s.pop();
		TreeNode *tmp = p->left; 
		p->left = p->right;
		p->right = tmp;
		if(p->left!=NULL)
		{
			s.push(p->left);
			cout<<p->val<<"left:"<<p->left->val<<endl;
		}
		if(p->right!=NULL){
			s.push(p->right);
			cout<<p->val<<"right:"<<p->right->val<<endl;
		}
	}
 } 

【22 从上到下打印二叉树】

题目描述

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:

1) 借助队列 存储 节点

vector<int> PrintFromTopToBottom(TreeNode* root) {  //层次遍历  借助 队列
	queue<TreeNode*> q;
	vector<int> result;
	if(root)
		q.push(root);
	while(!q.empty())
	{
		TreeNode* cur = q.front();
		q.pop();
		result.push_back(cur->val);
		if(cur->left)
		{
			q.push(cur->left);
		}
			
		if(cur->right)
		{
			q.push(cur->right);
		}
	}
	return result;
}

【23 二叉树的后序遍历】 

题目描述

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

bool VerifySquenceOfBST(vector<int> s) {
	if(s.size()==1)   
		return true;
	if(s.size()==0)   		//本题 认定,[] 为非二叉搜索树的后序遍历列表 
		return false;
	int mid=0,end = s.size()-1, i=0;
	while(mid<end && s[mid]<s[end])  //s[end]是根节点,是中间值
	{
		mid++;
	}
	vector<int> left,right;
	for(i=0;i<mid;i++)
	{
		left.push_back(s[i]);    //左子树的后序遍历列表
	}
	for(i=mid;i<end;i++)
	{
		if(s[i]<s[end])       // 右子树 比 根节点 大,返回 false,表示不满足二叉搜索树的特征
			return false;
		right.push_back(s[i]);  //右子树的后续遍历列表
	}
	bool l=true,r=true;
    // !! 递归 时判断 是不是 左/右子树 为空的情况,某一子树为空,则只需判断 右/左子树 的情况 
	if(!left.empty())			
		l = VerifySquenceOfBST(left);		
	if(!right.empty())
		r = VerifySquenceOfBST(right);
	return l&&r;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值