【数据结构——树】二叉树面试相关知识点总结(一)

本文详细介绍了二叉树的基本操作,包括二叉树节点定义、创建、遍历(前序、中序、后序及层序)、求节点个数、求深度等,并提供了递归与非递归的实现方法。

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

【1】二叉树节点定义

【2】前序创建二叉树


递归算法

【3】二叉树的前中后序遍历递归和非递归解法(属于深度搜索)

【4】层序遍历二叉树(按层次从上往下,从左往右)(属于广度搜索)


【5】求二叉树中的节点个数

【6】求二叉树的深度(剑指0ffer39)

【7】求二叉树的镜像:递归交换左右子女


【8】判断两棵二叉树是否结构相同

【9】判断二叉树是不是平衡二叉树

【10】判断二叉树是不是完全二叉树



【1】二叉树节点定义

struct BiTreeNode
{
	char data;
	BiTreeNode *lchild;
	BiTreeNode *rchild;
}; BiTreeNode *T;


【2】前序创建二叉树

/*************构建二叉树**************/

void CreateBiTree(BiTreeNode* &T)//按先序输入二叉树的节点,#代表空树
{
	char num;
	cin >> num;
	if('#' == num)
		T = NULL;
	else
	{
		T = new BiTreeNode;//产生新的子树
		T->data = num;
		CreateBiTree(T->lchild);//递归创建左子树
		CreateBiTree(T->rchild);//递归创建右子树
	}			
}



【3】二叉树的前中后序遍历递归解法


①前序遍历:如果二叉树不为空,访问根节点,前序遍历左子树,前序遍历右子树;否则,空操作

/*************先序递归遍历二叉树**************/
void PreOrderTraverse(BiTreeNode* &T){
	if(T)//节点不为空
	{
		cout << T->data;
		PreOrderTraverse(T->lchild);//递归遍历左子树
		PreOrderTraverse(T->rchild);//递归遍历右子树
	}
	else cout<<""; 
}

②中序遍历:如果二叉树不为空,中序遍历左子树,访问根节点,中序遍历右子树;否则,空操作

/*************中序递归遍历二叉树**************/
void InOrderTraverse(BiTreeNode* &T){
	if(T)
	{
		InOrderTraverse(T->lchild);//中序遍历左子树
		cout << T->data; //访问参数
		InOrderTraverse(T->lchild);//中序遍历右子树
	}
	else cout<<""; 
}


后序遍历:如果二叉树不为空,后序遍历左子树,后序遍历右子树,访问根节点;否则,空操作

/*****************后序递归遍历二叉树***************/  
void PosorderTraverse(BiTreeNode* &T){  
 if(T){  
  PosorderTraverse(T->lchild);//后序递归遍历左子树  
  PosorderTraverse(T->rchild);//后序递归遍历右子树  
  cout<<T->data;//访问根结点  
 }  
 else cout<<"";  
}  


<span style="font-size:12px;">
遍历的非递归实现

struct BiTreeNode{
	char data;
	BiTreeNode* lchild;
	BiTreeNode* rchild;
};

void CreateBiTree(BiTreeNode* &T)//按先序输入二叉树的节点,#代表空树  
{  
    char num;  
    cin >> num;  
    if('#' == num)  
        T = NULL;  
    else  
    {  
        T = new BiTreeNode;//产生新的子树  
        T->data = num;  
        CreateBiTree(T->lchild);//递归创建左子树  
        CreateBiTree(T->rchild);//递归创建右子树  
    }             
}


/*************【1】二叉树的前中后序遍历递归和非递归实现**************/  

/********************先序递归遍历二叉树********************
递归:节点为空就是递归出口,输出节点,遍历左孩子,遍历右孩子
非递归:
1.把根节点压栈,while循环栈不为空,设置指针,输出+弹出栈顶
2.若右孩子存在,压入右孩子
3.若左孩子存在,压入左孩子
************************************************************/ 


void preOrder(BiTreeNode* root)//递归
{
	if(root == NULL)return;
	cout << root->data <<endl;
	preOrder(root->lchild);
	preOrder(root->rchild);
}

void preOrder(BiTreeNode* root)//非递归,根左右,所以用栈,只要栈不空,就弹出
{
	if(!root)return;
	stack<BiTreeNode> s;
	s.push(root);

	while(!s.empty())//如果根节点存在
	{
		BiTreeNode* p = s.top();	//设一个指针用于遍历
		cout << p->data << endl;//先输出根节点
		s.pop();
		if(p->rchild)//先压入右孩子,再压入左孩子
			s.push(p->rchild);
		if(p->lchild)
			s.push(p->lchild);
	}
}

/********************中序递归遍历二叉树********************
递归:节点为空就是递归出口,遍历左孩子,输出节点,遍历右孩子
非递归:设置指针
1.while循环栈不为空或者节点不为空,
2.while节点存在,左孩子入栈
3.if栈不为空,输出栈顶元素,弹出,指针指向右孩子
************************************************************/ 
void InOrder(BiTreeNode* root)//递归
{
	if(root == NULL)return;
	InOrder(root->lchild);
	cout << root->data << endl;
	InOrder(root->rchild);
}

void InOrder(BiTreeNode* root)
{
	if(root == NULL)return;
	stack<BiTreeNode*>s;
	BiTreeNode* p = root;

	while(p!=NULL || !s.empty())
	{
		while(p!=NULL)
		{
			s.push(p);
			p=p->lchild;
		}
		if(!s.empty())
		{
			p = s.top();
			cout << p->data << endl;
			s.pop();
			p = p->rchild;
		}
	}
}

/********************后序递归遍历二叉树********************
递归:节点为空就是递归出口,遍历左孩子,遍历右孩子,输出节点
非递归:设置当前指针和前指针
1.while栈不为空,if为叶子节点,抑或前一节点是左孩子或右孩子,输出节点,变pre
2.否则 如果分别压入右节点、左节点
************************************************************/ 
void posOrder(BiTreeNode* root)
{
	if(root == NULL)return;
	posOrder(root->lchild);
	posOrder(root->rchild);
	cout << root->data << endl;
}

void posOrder(BiTreeNode* root)
{
	if(root == NULL)return;
	stack<BiTreeNode* > s;
	BiTreeNode* pre =NULL,*cur;
	s.push(root);

	while(!s.empty())
	{
		cur = s.top();
		if((cur->lchild ==NULL&&cur->rchild ==NULL)
			|| pre != NULL&&(pre == cur->lchild || pre ==cur->rchild) )
		{
			cout <<cur->data << endl;
			s.pop();
			pre =cur;
		}
		else
		{
			if(cur->rchild != NULL)
				s.push(cur->rchild);
			if(cur->lchild != NULL)
				s.push(cur->lchild);
		}
	}
}










int _tmain(int argc, _TCHAR* argv[])
{
	BiTreeNode* T = NULL;
	cout << "创建一颗树T,#表示空树" << endl;  
    CreateBiTree(T); 

	cout<<"中序递归遍历:"<<endl;   
    posOrder(T);  
    cout<<endl;  

	return 0;
}</span>


【4】二叉树的层序遍历

每一层从左向右输出,因为元素需要存储有先进先出的特性,所以选用队列。二叉树的层次遍历更像是一种广度优先搜索BFS

遍历的过程中将该层节点的孩子节点压入一个队列,这样就可以实现从上到下一层一层地遍历该二叉树。

每次将根节点入队列,当队列非空,则将front赋给临时指针pNode,继而输出根节点,接下来判断根节点左右孩子是否为空,非空则入队列,上述工作以后,再度从队列中取元素,队列空,则循环结束。

/******************层序遍历******************/
void LevelTraverse(BiTreeNode* &T)
{
	if(T==NULL)return;
	queue<BiTreeNode*> q;//创建队列来存储节点
	q.push(T);//
	while(!q.empty())//如果队列不为空
	{
		BiTreeNode* pNode = q.front();
		q.pop();
		cout << pNode->data;//访问节点
		if (pNode->lchild != NULL)
			q.push(pNode->lchild);
		if(pNode->rchild != NULL)
			q.push(pNode->rchild);
	
	}
	return;


}

【5】求二叉树中叶子节点的个数

递归解法:
(1)如果二叉树为空,返回0
(2)如果二叉树不为空且左右子树为空,返回1
(3)如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数

<span style="font-size:12px;">/*****************求二叉树中叶子节点的个数*****************************/
int LeavesCount(BiTreeNode* &T)
{
	if(T==NULL)return 0;

	if(T->lchild == NULL && T->rchild == NULL)return 1;
	int numLeft = LeavesCount(T->lchild);//左子树中叶子节点个数
	int numRight = LeavesCount(T->rchild);//右子树中叶子节点个数
	return(numLeft + numRight);

}</span><span style="font-size: 14px;">
</span>

【6】求二叉树的深度

深度即为递归左右子树的最大深度,如果节点为空则返回0,否则返回左右子树深度+1的最大值。

<span style="font-size:12px;">/**************求二叉树的深度**************/
int DepthOfBiTree(BiTreeNode* &T)
{
	if(T==NULL)return 0;//空树
	int ldepth = DepthOfBiTree(T->lchild);//左子树的深度
	int rdepth = DepthOfBiTree(T->rchild);//左子树的深度
	return (ldepth>rdepth)?(ldepth+1):(rdepth+1);

}</span>
【7】求二叉树镜像:递归交换左右子女

若有节点存在,且其左右子树有节点存在,就交换,然后递归交换~

/*****************递归交换左右子女*******************/
void exchangeChild(BiTreeNode* &T)
{
	if(T==NULL)return;
	BiTreeNode *temp = NULL;
	cout << T->data << " ";
	if(T->lchild||T->rchild)
	{
		temp = T->lchild;
		T->lchild = T->rchild;
		T->rchild = temp;
		exchangeChild(T->lchild);
		exchangeChild(T->rchild);

	}
	return;
}

【8】判断两棵二叉树是否结构相同

/******************判断两棵二叉树是否结构相同**********************/
bool equalBiTree(BiTreeNode* &T1,BiTreeNode* &T)
{ 

	if(T1 == NULL && T == NULL )return true;//都为空则相同
	else if(T1 == NULL || T == NULL )//一个为空一个不空,则不同
		return false;
	bool resultLeft = equalBiTree(T1->lchild,T->lchild);//比较左子树
	bool resultRight = equalBiTree(T1->rchild,T->rchild);//比较右子树
	return (resultLeft && resultRight); 


}

【9】判断是不是AVL平衡树

如果为空,则是

如果不为空,左右子树都是AVL且左右相差不大于1,则是

注意:主函数,传递参数时高度设置变量

	cout<<"T是否AVL平衡树:"<<endl; 
        int height=0;
	if(IsAvl(T,height))
		cout << "是AVL平衡树";
	else
		cout << "不是AVL平衡树";
	cout<<endl;
	


/**************************判断是不是AVL平衡树****************************/
bool IsAvl(BiTreeNode* &T,int &height)//还要判断左右子树高度是否差1
{
	if(T == NULL)
	{
		height = 0;
		return true;
	}

	int heightLeft;
	bool resultLeft = IsAvl(T->lchild,heightLeft);
	int heightRight;
	bool resultRight = IsAvl(T->rchild,heightRight);

	if(resultLeft && resultRight && abs(heightLeft - heightRight)<=1)//如果左右子树都为平衡树且高度差不大于1
	{
		height = max(heightLeft, heightRight)+1;
		return true;
	}
	else
	{
		height = max(heightLeft, heightRight) + 1;  
        return false;  
	}

}

【10】判断是否完全二叉树

首先,完全二叉树是指若二叉树深度为h,第h-1层节点数都是最大个数,第h层所有节点都集中再最左边。

算法原理:按层次遍历二叉树,建立队列来保存节点。

如果队列不为空,从第一个根节点开始遍历。

1.如果节点没有子树,则判断左右子树节点是否为空,有则不是。

2.如果有子树,左右子树都不为空,则继续遍历。

左不空,右空,左子树压入队列,继续

若左空右不空,不是。

若左右都空,则是。


/**************************判断是不是完全二叉树****************************/
bool IsCompleteBinaryTree(BiTreeNode* &T)
{
	if(T == NULL)return false;
	queue<BiTreeNode*> q;//创建队列来存储节点
	q.push(T);
	bool mustHaveNoChild = false;
	bool result = true;
	while(!q.empty())//如果队列不为空
	{
		BiTreeNode* pNode = q.front();//队列头结点为指针
		q.pop();//把头结点出列
		if(mustHaveNoChild)//如果该节点没有子树
		{
			if(pNode->lchild != NULL || pNode->rchild != NULL)
			{
				result = false;//如果左子树或右子树不为空,则不是完全二叉树
				break;
			}
		}
		else//如果该节点有子树
		{
			if(pNode->lchild != NULL && pNode->rchild != NULL)//左右子树都不为空
			{
				q.push(pNode->lchild);
				q.push(pNode->rchild);
			}
			else if(pNode->lchild != NULL && pNode->rchild == NULL)//左子树不为空,右子树为空
			{
				mustHaveNoChild = true;
				q.push(pNode->lchild);
			}
			else if(pNode->lchild == NULL && pNode->rchild != NULL)//左子树为空,右子树不为空
			{
				 result = false;  
				 break;  
			}
			else//左右子树都为空
			{  
					   mustHaveNoChild = true;  
			} 

		}
	}
	return result;
}


cout<<"T是否完全二叉树:"<<endl; 

	if(IsCompleteBinaryTree(T))
		cout << "是完全二叉树";
	else
		cout << "不是完全二叉树";
	cout<<endl;



#include<iostream>
#include<queue>

using namespace std;


/***************定义二叉树****************/
struct BiTreeNode
{
	char data;
	BiTreeNode *lchild;
	BiTreeNode *rchild;
};

 BiTreeNode *T;
 BiTreeNode *T1,*T2;

/*************构建二叉树**************/

void CreateBiTree(BiTreeNode* &T)//按先序输入二叉树的节点,#代表空树
{
	char num;
	cin >> num;
	if('#' == num)
		T = NULL;
	else
	{
		T = new BiTreeNode;//产生新的子树
		T->data = num;
		CreateBiTree(T->lchild);//递归创建左子树
		CreateBiTree(T->rchild);//递归创建右子树
	}			
}


/*************先序递归遍历二叉树**************/
void PreOrderTraverse(BiTreeNode* &T){
	if(T)//节点不为空
	{
		cout << T->data;
		PreOrderTraverse(T->lchild);//递归遍历左子树
		PreOrderTraverse(T->rchild);//递归遍历右子树
	}
	else cout<<""; 
}

/*************中序递归遍历二叉树**************/
void InOrderTraverse(BiTreeNode* &T){
	if(T!=NULL)
	{
		InOrderTraverse(T->lchild);//中序遍历左子树
		cout << T->data; //访问参数
		InOrderTraverse(T->lchild);//中序遍历右子树
	}
	else cout<<""; 
}
/*****************后序递归遍历二叉树***************/  
void PosorderTraverse(BiTreeNode* &T){  
 if(T){  
  PosorderTraverse(T->lchild);//后序递归遍历左子树  
  PosorderTraverse(T->rchild);//后序递归遍历右子树  
  cout<<T->data;//访问根结点  
 }  
 else cout<<"";  
}  

/******************层序遍历******************/
void LevelTraverse(BiTreeNode* &T){
	if(T==NULL)return;
	queue<BiTreeNode*> q;//创建队列来存储节点
	q.push(T);//
	while(!q.empty())//如果队列不为空
	{
		BiTreeNode* pNode = q.front();
		q.pop();
		cout << pNode->data;//访问节点
		if (pNode->lchild != NULL)
			q.push(pNode->lchild);
		if(pNode->rchild != NULL)
			q.push(pNode->rchild);	
	}
	return;
}

/**************************判断是不是完全二叉树****************************/
bool IsCompleteBinaryTree(BiTreeNode* &T)
{
	if(T == NULL)return false;
	queue<BiTreeNode*> q;//创建队列来存储节点
	q.push(T);
	bool mustHaveNoChild = false;
	bool result = true;
	while(!q.empty())//如果队列不为空
	{
		BiTreeNode* pNode = q.front();//队列头结点为指针
		q.pop();//把头结点出列
		if(mustHaveNoChild)//如果该节点没有子树
		{
			if(pNode->lchild != NULL || pNode->rchild != NULL)
			{
				result = false;//如果左子树或右子树不为空,则不是完全二叉树
				break;
			}
		}
		else//如果该节点有子树
		{
			if(pNode->lchild != NULL && pNode->rchild != NULL)//左右子树都不为空
			{
				q.push(pNode->lchild);
				q.push(pNode->rchild);
			}
			else if(pNode->lchild != NULL && pNode->rchild == NULL)//左子树不为空,右子树为空
			{
				mustHaveNoChild = true;
				q.push(pNode->lchild);
			}
			else if(pNode->lchild == NULL && pNode->rchild != NULL)//左子树为空,右子树不为空
			{
				 result = false;  
				 break;  
			}
			else//左右子树都为空
			{  
					   mustHaveNoChild = true;  
			} 

		}
	}
	return result;
}


/*****************求二叉树中叶子节点的个数*****************************/
int LeavesCount(BiTreeNode* &T)
{
	if(T==NULL)return 0;

	if(T->lchild == NULL && T->rchild == NULL)return 1;
	int numLeft = LeavesCount(T->lchild);//左子树中叶子节点个数
	int numRight = LeavesCount(T->rchild);//右子树中叶子节点个数
	return(numLeft + numRight);

}

/**************求二叉树的深度**************/
int DepthOfBiTree(BiTreeNode* &T)
{
	if(T==NULL)return 0;//空树
	int ldepth = DepthOfBiTree(T->lchild);//左子树的深度
	int rdepth = DepthOfBiTree(T->rchild);//左子树的深度
	return (ldepth>rdepth)?(ldepth+1):(rdepth+1);

}

/*****************递归交换左右子女*******************/
void exchangeChild(BiTreeNode* &T)
{
	if(T==NULL)return;
	BiTreeNode *temp = NULL;
	cout << T->data << " ";
	if(T->lchild||T->rchild)
	{
		temp = T->lchild;
		T->lchild = T->rchild;
		T->rchild = temp;
		exchangeChild(T->lchild);
		exchangeChild(T->rchild);

	}
	return;
}

/******************判断两棵二叉树是否结构相同**********************/
bool equalBiTree(BiTreeNode* &T1,BiTreeNode* &T)
{ 

	if(T1 == NULL && T == NULL )return true;//都为空则相同
	else if(T1 == NULL || T == NULL )//一个为空一个不空,则不同
		return false;
	bool resultLeft = equalBiTree(T1->lchild,T->lchild);//比较左子树
	bool resultRight = equalBiTree(T1->rchild,T->rchild);//比较右子树
	return (resultLeft && resultRight); 


}

/**************************判断是不是AVL平衡树****************************/
bool IsAvl(BiTreeNode* &T,int &height)//还要判断左右子树高度是否差1
{
	if(T == NULL)
	{
		height = 0;
		return true;
	}

	int heightLeft;
	bool resultLeft = IsAvl(T->lchild,heightLeft);
	int heightRight;
	bool resultRight = IsAvl(T->rchild,heightRight);

	if(resultLeft && resultRight && abs(heightLeft - heightRight)<=1)//如果左右子树都为平衡树且高度差不大于1
	{
		height = max(heightLeft, heightRight)+1;
		return true;
	}
	else
	{
		height = max(heightLeft, heightRight) + 1;  
        return false;  
	}

}









int main(){

	cout << "创建一颗树T,#表示空树" << endl;
	CreateBiTree(T);
	cout << "创建一颗树T1,#表示空树" << endl;
	CreateBiTree(T1);

	cout<<"先序递归遍历:"<<endl;  
	PreOrderTraverse(T);  
	cout<<endl; 

	cout<<"中序递归遍历:"<<endl; 
	InOrderTraverse(T);  
	cout<<endl;  

	cout<<"后序递归遍历:"<<endl;  
	PosorderTraverse(T);  
	cout<<endl;

	cout<<"层序递归遍历:"<<endl;  
	LevelTraverse(T);  
	cout<<endl;

	cout<<"叶子节点个数:"<<endl;  
	cout << LeavesCount(T);  
	cout<<endl;

	cout<<"二叉树深度:"<<endl;  
	cout << DepthOfBiTree(T);  
	cout<<endl;

	cout<<"递归交换左右子女:"<<endl;  
	exchangeChild(T);  
	cout<<endl;

	cout<<"T和T1是否结构相同?"<<endl;  
	if(equalBiTree(T1,T))
		cout << "两者相同";
	else
		cout << "两棵树结构不同";
	cout<<endl;


	cout<<"T是否AVL平衡树:"<<endl; 
   int	height=0;
	if(IsAvl(T,height))
		cout << "是AVL平衡树";
	else
		cout << "不是AVL平衡树";
	cout<<endl;
	
	cout<<"T是否完全二叉树:"<<endl; 

	if(IsCompleteBinaryTree(T))
		cout << "是完全二叉树";
	else
		cout << "不是完全二叉树";
	cout<<endl;

	system("pause");
	return 0;
} 




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值