做了一些实验题目,经常会出现有关对二叉树的相关操作,在这里总结一下。
1、数据结构
二叉树是一种特殊的数据结构,包括根结点、左子树、右子树。构造数据结构时,我们需要定义结点所要存储的信息包括:结点存储的数据值、指向其后继左右子树的指针。
typedef struct BiNode{
int data;///存储当前结点的数据值
struct BiNode *lchild,*rchild;///指向其左右子树的结点类型指针
}BiNode,*BiTree;
2、二叉树的创建
根据二叉树的两种不同遍历组合可以确定唯一一棵二叉树,常用的有:先(前)序、中序遍历法创建,后序、中序遍历法创建。
///前序中序建立二叉树
BiTree CreateBiTree1(int a[],int b[],int n){
if(n==0)
return NULL;
BiTree T=(BiNode*)malloc(sizeof(BiNode));///C语言动态方法开辟空间,也可以用C++的new方法
T->data=a[0];
int i;
for(i=0;i<n;i++){
if(a[0]==b[i])
break;
}
T->lchild=CreateBiTree1(a+1,b,i);///递归创建左右子树
T->rchild=CreateBiTree1(a+i+1,b+i+1,n-i-1);
return T;
}
///后序与中序创建树
BiTree CreateBiTree2(int a[],int b[],int n){
if(n==0)
return NULL;
BiTree T=(BiNode*)malloc(sizeof(BiNode));
T->data=a[n-1];
int i;
for(i=0;i<n;i++){
if(a[n-1]==b[i])
break;
}
T->lchild=CreateBiTree2(a,b,i);
T->rchild=CreateBiTree2(a+i,b+i+1,n-i-1);
return T;
}
3、二叉树的遍历
按照一定的顺序规则输出已经构建的二叉树的结点信息,包括先序遍历(先访问根结点)、中序遍历(根结点的访问顺序在中间)、后续遍历(根结点的访问顺序在最后)、层次遍历。
///前序遍历:先遍历根结点,再依次遍历左右子树
void PreTraver(BiTree T){
if(T){
cout<<T->data<<" ";///输出根结点值
PreTraver(T->lchild);///递归遍历左子树
PreTraver(T->rchild);///递归遍历右子树
}
}
//前序非递归
void PreTracer(BiTree T) {
stack<BiTree>st;
BiTree ptr = T;
while(ptr || !st.empty()) {
if(ptr) {
cout<<ptr->val<<" ";
st.emplace(ptr);
ptr = ptr->left;
} else {
ptr = st.top();
st.pop();
ptr = ptr->right;
}
}
}
if(!root) return {};
vector<int>ret;
stack<TreeNode*> st;
TreeNode* ptr = root;
while(ptr || !st.empty()) {
if(ptr) {
ret.emplace_back(ptr->val);
st.emplace(ptr);
ptr = ptr->left;
} else {
ptr = st.top();
st.pop();
ptr = ptr->right;
}
}
return ret;
///中序遍历:先遍历左子树,再依次遍历根结点、右子树
void MidTraver(BiTree T){
if(T){
MidTraver(T->lchild);
cout<<T->data<<" ";
MidTraver(T->rchild);
}
}
///中序非递归
void vector<int> inorderTraversal(BiTree T) {
stack<BiTree>st;
while(T != NULL || !st.empty()) {
while(T != NULL) {
st.emplace(T);
T = T->left;
}
if(!st.empty()) {
T = st.top();
cout<<T->data<<" ";
st.pop();
T = T->right;
}
}
}
///后序遍历:先依次遍历左右子树,再遍历根结点
void EndTraver(BiTree T){
if(T){
EndTraver(T->lchild);
EndTraver(T->rchild);
cout<<T->data<<" ";
}
}
///层次遍历:从根结点开始从上往下逐层遍历,类似于图的广度优先遍历
void LevelTraver(BiTree T){
if(!T)
return;
queue<BiTree>q;
q.push(T);
while(!q.empty()){
if(q.front()->lchild!=NULL)
q.push(q.front()->lchild);
if(q.front()->rchild!=NULL)
q.push(q.front()->rchild);
cout<<q.front()->data<<" ";
q.pop();
}
}
4、统计叶子结点数
叶子结点就是指左右子树均为空的结点,根据左右子树为空这一特征进行查找计算。
///计算叶子数量
///借助递归
int CountLeaves1(BiTree T){
if(!T)
return 0;
else if(!T->lchild&&!T->rchild)///左右子树为空,当前借点为叶子结点
return 1;
else
return CountLeaves1(T->rchild)+CountLeaves1(T->rchild);///左右子树结点数加和
}
///借助层次遍历:逐层遍历,满足叶子结点定义则进行加和
int CountLeaves2(BiTree T){
int t=0;
if(!T)
return 0;
queue<BiTree>q;
q.push(T);
while(!q.empty()){
if(!q.front()->lchild&&!q.front()->rchild)
t++;
if(q.front()->lchild!=NULL)
q.push(q.front()->lchild);
if(q.front()->rchild!=NULL)
q.push(q.front()->rchild);
q.pop();
}
return t;
}
5、计算二叉树的深度
二叉树最深结点所在的层数。
///计算树的深度:递归计算左右子树深度,左右子树的最大深度即为二叉树的深度
int CountDepth(BiTree T){
int depth1,depth2;
if(!T)
return 0;
depth1=CountDepth(T->lchild);
depth2=CountDepth(T->rchild);
return depth1>depth2?depth1+1:depth2+1;
}
6、二叉树左右子树交换
将二叉树的左右子树、子树的子树……进行交换。
///子树交换
void ExChange(BiTree T){
BiTree p;
if(T){
p=T->lchild;
T->lchild=T->rchild;
T->rchild=p;
ExChange(T->lchild);
ExChange(T->rchild);
}
}
综上所述,完整程序如下:
///二叉树相关基本操作
#include<bits/stdc++.h>
using namespace std;
///创建结构体
typedef struct BiNode{
int data;
struct BiNode *lchild,*rchild;
}BiNode,*BiTree;
///前序中序建立二叉树
BiTree CreateBiTree1(int a[],int b[],int n){
if(n==0)
return NULL;
BiTree T=(BiNode*)malloc(sizeof(BiNode));
T->data=a[0];
int i;
for(i=0;i<n;i++){
if(a[0]==b[i])
break;
}
T->lchild=CreateBiTree1(a+1,b,i);
T->rchild=CreateBiTree1(a+i+1,b+i+1,n-i-1);
return T;
}
///后序与中序创建树
BiTree CreateBiTree2(int a[],int b[],int n){
if(n==0)
return NULL;
BiTree T=(BiNode*)malloc(sizeof(BiNode));
T->data=a[n-1];
int i;
for(i=0;i<n;i++){
if(a[n-1]==b[i])
break;
}
T->lchild=CreateBiTree2(a,b,i);
T->rchild=CreateBiTree2(a+i,b+i+1,n-i-1);
return T;
}
///前序遍历
void PreTraver(BiTree T){
if(T){
cout<<T->data<<" ";
PreTraver(T->lchild);
PreTraver(T->rchild);
}
}
///中序遍历
void MidTraver(BiTree T){
if(T){
MidTraver(T->lchild);
cout<<T->data<<" ";
MidTraver(T->rchild);
}
}
///后序遍历
void EndTraver(BiTree T){
if(T){
EndTraver(T->lchild);
EndTraver(T->rchild);
cout<<T->data<<" ";
}
}
///层次遍历
void LevelTraver(BiTree T){
if(!T)
return;
queue<BiTree>q;
q.push(T);
while(!q.empty()){
if(q.front()->lchild!=NULL)
q.push(q.front()->lchild);
if(q.front()->rchild!=NULL)
q.push(q.front()->rchild);
cout<<q.front()->data<<" ";
q.pop();
}
}
///计算叶子数量
///借助递归
int CountLeaves1(BiTree T){
if(!T)
return 0;
else if(!T->lchild&&!T->rchild)
return 1;
else
return CountLeaves1(T->rchild)+CountLeaves1(T->rchild);
}
///借助层次遍历
int CountLeaves2(BiTree T){
int t=0;
if(!T)
return 0;
queue<BiTree>q;
q.push(T);
while(!q.empty()){
if(!q.front()->lchild&&!q.front()->rchild)
t++;
if(q.front()->lchild!=NULL)
q.push(q.front()->lchild);
if(q.front()->rchild!=NULL)
q.push(q.front()->rchild);
q.pop();
}
return t;
}
///计算树的深度
int CountDepth(BiTree T){
int depth1,depth2;
if(!T)
return 0;
depth1=CountDepth(T->lchild);
depth2=CountDepth(T->rchild);
return depth1>depth2?depth1+1:depth2+1;
}
///子树交换
void ExChange(BiTree T){
BiTree p;
if(T){
p=T->lchild;
T->lchild=T->rchild;
T->rchild=p;
ExChange(T->lchild);
ExChange(T->rchild);
}
}
int main(){
///借助数组创建
int n;
cin>>n;
int a[n],b[n];
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
cin>>b[i];
BiTree T=NULL;
T=CreateBiTree1(a,b,n);
///T=CreateBiTree2(a,b,n);
cout<<"前序遍历:";
PreTraver(T);
cout<<"\n中序遍历:";
MidTraver(T);
cout<<"\n后序遍历:";
EndTraver(T);
cout<<"\n层次遍历:";
LevelTraver(T);
cout<<"\n叶子数量1:"<<CountLeaves1(T);
cout<<"\n叶子数量2:"<<CountLeaves2(T);
cout<<"\n深度为:"<<CountDepth(T);
ExChange(T);
cout<<"\n子树交换后层次遍历:";
LevelTraver(T);
return 0;
}