2叉树题-1

本文详细介绍了二叉树的各种遍历方法(前序、后序、中序及字形打印)、搜索树的后序遍历验证、单值二叉树判断、镜像转换、二叉树结构相似性、高度平衡性检测等核心算法。通过递归和非递归实现,深入解析了这些技术在实际编程中的应用。

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


在任意一棵非空二叉排序树T1中,删除某结点v之后形成二叉排序树T2,再将v插入T2形成二叉排序树T3。
若v是T1的叶结点,则T1与T3相同1.若v不是T1的叶结点,则T1与T3不同

144.前序遍历

//Note: The returned array must be malloced, assume caller calls free().
//给数组开空间

int Treesize( struct TreeNode*root){
if(root == NULL)
return 0;
return 1 + Treesize(root->left) + Treesize(root->right);}

//前序遍历
void _preorderTraversal( struct TreeNode* root,int* array,int* pi)
{if(root == NULL)
return;//因为是void _preorderTraversal所以返回的不是 return 0
//return;不带返回值的return语句
//return 0;带返回值的return语句,或者返回一个变量或一个函数。
array[ (*pi)++] = root->val;
//方法1(错误):传值,传值过程中 ,每个递归里都有1个i,我的(上1个递归函数)i传给你(下1个递归函数),你+了,但不会影响我,我没有+,
//方法2(正确):只能有一个i,传地址,每次解引用之后 是同一个i,使用pi指针,这样在递归得过程中,对同一个下标i++
_preorderTraversal( root->left, array ,pi);
_preorderTraversal( root->right,array,pi);}

int* preorderTraversal(struct TreeNode *root, int* returnsize){
int size = Treesize(root);
int* array = ( int*)malloc(sizeof(int)*size);int i = 0;
_preorderTraversal(root,array,&i);
*returnsize = size ;
return array;}

非递归:

class Solution {
public:
	vector<int> preorderTraversal(TreeNode*root) {
		vector<int> v;
		stack<TreeNode*> st;
		TreeNode*cur = root;
// cur不为空,表示还有树没有开始访问,st不为空,表示还有节点的右子树没有访问
        while(cur || !st.empty())
		{
// 1、访问左路节点并保存进栈里,把节点压栈为了左路节点都访问完之后回来访问右路子树
			while (cur)
			{
				v.push_back(cur->val);
				st.push(cur);
				cur = cur->left;
			}
// 2、对于root这棵树,乘下的是左路节点的右子树没有访问
//依次从栈里面拿出来左路节点,访问其右子树
			TreeNode*top = st.top();
			st.pop();
// 右树
			cur = top->right;
		}
		return v;
	}
};

访问左路节点1 2 12 并保存进栈里,弹出12 ,访问12的右子树,访问4的左子树5,再访问6,再访问2的右,
请添加图片描述

145. 后序遍历

class Solution {
public:
    vector<int> postorderTraversal(TreeNode*root) {
	vector<int> v;
	TreeNode* prev = nullptr;
	stack<TreeNode*> st;
	TreeNode*cur = root;
	while (cur || !st.empty())
	{
		//保存左路节点进栈
		while (cur)
		{
			st.push(cur);
			cur = cur->left;
		}54
		//对于root这棵树,剩下的是左路节点和左路节点右子树没有访问
		//依次从栈里面拿出来访问
		TreeNode* top = st.top();
		//如果右为空,或者右孩子等于上一个访问的节点,则右树都访问过了
		//取出当前节点访问
		if (top->right == nullptr || top->right == prev)
		{
			v.push_back(top->val); st.pop();
			prev = top;
			cur = nullptr;
		}
		else{
			//右树
			cur = top->right;
		}
	}
	return v;
}
};

凡是右不为空,都会两次经过这个节点,要想办法区分:两次经过4,第1次经过时,4的右还没有访问,访问右;第2次经过时,4的右已经访问,访问4,再把4出栈。
if 他的右孩子(6)等于上一个访问的节点(5),那么他的右树已经访问过了,应该放他本身, else他的右孩子(6)不等于上一个访问的节点(5),那么他的右树还没有访问,访问(6)右树。

KY11 中序遍历

#include<stdio.h>
#include<stdlib.h>
typedef struct TreeNode
{
     char _val;
    struct TreeNode* pleft;
    struct TreeNode* pright;
}TreeNode;

TreeNode* CreateTree(char* arr,int *pi)
{
     if (arr[*pi] == '#')
     {
         return NULL;
     }
     else
     {
     TreeNode * root = (TreeNode *)malloc (sizeof(TreeNode));
         root->_val = arr[*pi] ;
         ++(*pi);
         root->pleft = CreateTree(arr,pi);
           ++(*pi);
         root->pright = CreateTree(arr,pi);
         return root;
     } 
}
void InorderTraversal(TreeNode * root)
{
    if (root == NULL)
    {
        return ;
    }
    InorderTraversal(root->pleft);
    printf("%c ",root->_val);
    InorderTraversal(root->pright);
}

int main()
{
     char arr[100];
     scanf("%s",arr);
     int i = 0;
     TreeNode * root = CreateTree(arr,&i);
     InorderTraversal(root);
     return 0;
}

之字形顺序打印二叉树

添加链接描述
当前层从左向右遍历访问,下层就从left到right入栈;当前层如果从右向左遍历,下层就从right到 left入栈。first:先入栈 ,second:后入栈。
v.push_back:访问完第1层;q.push:第2层;队列里的节点放入到栈;访问第2层:v.push_back
在这里插入图片描述
栈:[3 2]:访问3时,先入6;再访问2时,先入队列5 再入队列4,即[6 5 4];放入栈:[4 5 6]

vector<vector<int> > Print(TreeNode* pRoot) {
	vector<vector<int> > result; 
	if (pRoot == nullptr)
	{ return result; }
	stack<TreeNode*> st; //保存要遍历的节点  栈
	queue<TreeNode*> q; //临时队列:辅助,stack不能既用来出,又用来进
	st.push(pRoot);
int dir = 1; //方向dir=1. 入栈顺序从left开始. 2.入栈顺序从right开始.
	vector<int> v; 保存临时节点 
while(!st.empty())
{
int size = st.size();
	for(int i = 0; i < size; i++)
	{ //清空本轮stack结构,并遍历,stack本身有逆序的功能 
		TreeNode *curr = st.top(); 
		st.pop(); 把栈顶元素pop
		v.push_back(curr->val); 把pop出的元素放入v
		TreeNode *first = (dir == 1)?curr->left:curr->right; 
		TreeNode *second = (dir == 1)?curr->right:curr->left; 
//将下一轮访问顺序放入q中 层序遍历 
		if(first != nullptr) 
			q.push(first); 
		if(second != nullptr)
			q.push(second); 
	}//将1层符合要求的所有节点,入result
	 result.push_back(v); 
//将下一轮访问节点入栈,进行逆序 
while(!q.empty())
{ st.push(q.front());把队列里的内容放入栈,q.front():队列的头节点
q.pop(); }//一层遍历完毕,就要更改入栈顺序: 
dir = (dir == 1)? 2 : 1;
v.clear(); 
}
	return result;
}

层序

102.二叉树的层序遍历:
方法1:P21第21页:q.size();//获取当前层的数据个数//当前层出完以后,队列中存的就是下一层的所有节点。队列里面只保存一层节点。for循环:1层里的细节。 { //pop完本层all节点,压入下一层all节点。边出队列边入队列。 q.pop(); //去掉当前节点 。
方法2:

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>>vv; 
if (root == nullptr)
return vv;
vector<TreeNode* > curV; 
vector<TreeNode*> nextV;
curV.push_back(root); 
while (!curV.empty())
{
	vector<int> v;
	for (auto e : curV)
	{
		v.push_back(e->val); 
		if (e->left)
			nextV.push_back(e->left);
		if (e->right)
			nextV.push_back(e->right);
	}
	vv.push_back(v);
	curV.swap(nextV);
	nextV.clear( );
}
return vv;}
};

nextV、curV里放的是节点,不是值,而要求返回的是节点的值
请添加图片描述

从上往下打印二叉树 层序遍历

添加链接描述

vector<int> PrintFromTopToBottom(TreeNode* root) {
	if (root == nullptr)
	{ return vector<int>(); 
	}
	vector<int> v;
	queue<TreeNode*> q; 队列 先进先出
	q.push(root); 
	while (!q.empty())
	{
	TreeNode *father = q.front();
	q.pop();出节点
	 v.push_back(father->val);访问节点
	if (father->left){ //左子树不为空 ,当前节点的左入队
		q.push(father->left); }
	if(father->right){//右子树不为空,当前节点的右入队
		q.push(father->right); }
	}
	return v; 
}

搜索树BST 后序遍历

添加链接描述
后序序列S,最后一个元素是x (root节点),如果去掉最后一个元素的序列为 T,T满足:T分成两段,前一段(左子树)小于x,后一段(右子树)大于x,且这两段(子树)都是合法的后序序列 //验证思路:当前序列,及其子序列必须都满足上述定义。闭区间,

bool VerifySquenceOfBSTCore(vector<int> &sequence, int start, int end){
	if (start >= end)
		{ 
		//在不断查找过程中,区域不断缩小,为空时,证明之前的所有范围都满足检测条件
		//也就是是一个BST
		 return true; }//拿到root节点的值 
		int root = sequence[end]; 
		//先遍历左半部分,也就是整体都要比root小,拿到左子树序列 
		int i = start;
		while(i < end && sequence[i] < root)
		{ i++; }
		//在检测右子树是否符合大于root的条件,要从i开始,也就是右半部分的开始
		for(int j = i; j < end; j++)
		{ if(sequence[j] < root)
		{ 
			//在合法位置处,当前值小于root,不满足BST定义 
			return false; 
		} 
		}//走到这里,就说明,当前序列满足需求。但并不代表题目被解决了,还要在检测left和right各自是否也满足 
		return VerifySquenceOfBSTCore(sequence, 0, i-1) && VerifySquenceOfBSTCore(sequence, i, end-1);
	}
bool VerifySquenceOfBST(vector<int> sequence)
{ if(sequence.empty())
{ return false; }
return VerifySquenceOfBSTCore(sequence, 0, sequence.size()-1); 
}sequence.size()-1:若有5个元素,最后1个的下标:4

965.单值二叉树

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时,才返回true;否则返回false 。输入:[1,1,1,1,1,null,1]输出:true

/* Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right; * }; */
bool isUnivalTree( struct TreeNode* root){
if( root == NULL)
return true;//左是空=右是空,具有相同的值,这个值是空
//大框架是前序遍历(根 左右子树 ),切分子树
//当前树
if(root->left && root->val != root->left->val)
return false;
if(root->right &&root->val != root->right->val)
return false;
//递归判断左右子树
return isUnivalTree(root->left) && isUnivalTree(root->right);}

226.求二叉树的镜像

struct TreeNode* invertTree(struct TreeNode* root){
if(root == NULL){
return NULL;}
else{//方法2:中序和后序结合
struct TreeNode* right = root->right;//先复制1个右,否则下面左右交换时,会把原来的右覆盖掉
root->right = invertTree( root->left);
root->left = invertTree(right);
return root;}}

100.2个二叉树是否相同。

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(p == NULL && q == NULL)
return true;//不仅这里可能返回true,最后那个return也可能返回true
//结构不同
if(p == NULL && q != NULL)
return false;
//结构不同
if(p != NULL && q == NULL)
return false;
//值不同
if(p->val != q->val)
return false;
//递归开始,以叶子节点2为例:左=空 && 右=空,返回true给2
return isSameTree(p->left,q->left)
&& isSameTree(p->right, q->right )}

572.s 中是否包含和t具有相同结构和节点值的子树。

添加链接描述
二叉树都是递归定义的,所以递归操作是比较常见的做法,1. 先确定起始位置 //2. 在确定从该位置开始,后续的左右子树的内容是否一致
和当前节点不一样,但可能和其左(右)子树是一样的
//遍历每个节点所在的子树,每个节点当作根,都比较一下

bool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(p == NULL && q == NULL)
return true;
if(p == NULL && q != NULL)
return false;
if(p != NULL && q == NULL)
return false;
if(p->val != q->val)
return false;
return isSameTree(p->left,q->left)
&& isSameTree(p->right, q->right );
}
bool isSubtree(struct TreeNode* s, struct TreeNode* t){
if( s == NULL)
return false;
if( isSameTree(s, t))
return true;
return isSubtree( s->left, t) || isSubtree(s->right, t);
}

110.是否是高度平衡

在这里插入图片描述
//方法2:从叶子开始,倒着往上走;左右2边一旦有 1个false则不计算gap;后序判断,判断的同时把高度带给上一层的父亲,过程如上图;优化到最坏是 o(N)

bool _isBalanced(struct TreeNode* root,int* pDepth){
if(root == NULL){
* pDepth=0;
return true;}
else{
int leftDepth = 0;
if(_isBalanced( root->left,&leftDepth) == false)
return false;
int rightDepth = 0;
if(_isBalanced(root->right,&rightDepth) == false)
return false;
//左右树都满足,开始判断当前树,返回false时,高度已经不重要了
if(abs ( leftDepth - rightDepth) > 1)
return false;
*pDepth = leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
return true;//只有返回true时,才算高度
}}
bool isBalanced ( struct TreeNode*root){
int depth = 0;
return _isBalanced(root, &depth) ;
}

error: non-void function does not return a value in all control paths [-Werror,-Wreturn-type]:函数并不是所有分支都有返回值。只包括了y=0 、1、2,三种情况,事实上由于输入参数number是整数,确实也只有这三种情况,但编译器不这样认为,编译器认为还存在其他情况,所以把 else if(y==2)改称else就能包含所有情况了,编译也就不会出现有的情况没有返回值的情况了。没给返回值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值