【1】二叉树节点定义
【2】前序创建二叉树
递归算法
【3】二叉树的前中后序遍历递归和非递归解法(属于深度搜索)
【4】层序遍历二叉树(按层次从上往下,从左往右)(属于广度搜索)
【5】求二叉树中的节点个数
【6】求二叉树的深度(剑指0ffer39)
【7】求二叉树的镜像:递归交换左右子女
【8】判断两棵二叉树是否结构相同
【9】判断二叉树是不是平衡二叉树
【10】判断二叉树是不是完全二叉树
【1】二叉树节点定义
struct BiTreeNode
{
char data;
BiTreeNode *lchild;
BiTreeNode *rchild;
}; BiTreeNode *T;
/*************构建二叉树**************/
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;
}