数据结构——二叉树操作
本次博客,我将记录数据结构中的二叉树操作及其代码
[1]定义
1.定义二叉树结点
struct BiNode{
ElemType data; //数据元素
BiNode *lchild; //指向左子树的指针
BiNode *rchild; //指向右子树的指针
int pushNum=0; //针对非递归后序遍历设置的标志位, 表示入栈的次数
};
2.定义二叉树
class BiTree{
private:
void createNode(BiNode *&t); //创建二叉树的递归函数
void deleteNode(BiNode *t); //删除二叉树结点的递归函数
int height(BiNode *t); //计算二叉树高度的递归函数
int numOfLeaf(BiNode *t); //计算叶子结点数的递归函数
int numOfNodes(BiNode *t); //计算结点数的递归函数
BiNode* search(BiNode *t, ElemType e); //查找值为e的结点的递归函数
void preOrder(BiNode *t); //先序遍历递归函数
void inOrder(BiNode *t); //中序遍历递归函数
void postOrder(BiNode *t); //后序遍历递归函数
public:
BiTree(); //构造函数
~BiTree(); //析构函数
BiNode* root; //根结点
void createBiTree(); //创建二叉树
void deleteBiTree(); //删除二叉树
int heightOfBiTree(); //计算二叉树的高度
int numOfBTLeaf(); //计算二叉树的叶子结点数
int numOfBTNodes(); //计算二叉树的结点数
int numOfBTNodesDegree2(); //计算二叉树度为2的结点数
BiNode* searchBTNode(ElemType e); //在二叉树中查找值为e的结点
void preOrderBTTraverse(); //递归:先序遍历二叉树
void inOrderBTTraverse(); //递归:中序遍历二叉树
void postOrderBTTraverse(); //递归:后序遍历二叉树
void preOrderBTTraverse_NonRec(); //非递归:先序遍历二叉树
void inOrderBTTraverse_NonRec(); //非递归:中序遍历二叉树
void postOrderBTTraverse_NonRec(); //非递归:后序遍历二叉树
void levelOrderTraverse(); //非递归:层次遍历二叉树
int numOfBTLeaf_NonRec(); //非递归:计算二叉树的叶子结点数
};
3.一些其他操作
class Solution{
public:
void exchangeSubTree(BiNode *&t); //交换二叉树的左子树和右子树
bool isSimilar(BiNode *a, BiNode *b); //判断两棵二叉树是否相似
//二叉树的递归拷贝
void copyBiNode(BiNode *t, BiNode *&p);
void copyBiTree1(BiTree *t, BiTree *&p);
//二叉树的非递归拷贝
void copyBiTree2(BiTree *t, BiTree *&p);
};
[2]实现
1.二叉树的构造和析构函数
BiTree::BiTree(){
root=nullptr;
}
BiTree::~BiTree(){
if(root){
deleteNode(root);
}
}
2.递归创建二叉树
void BiTree::createNode(BiNode *&t){
//输入该结点的数据,若为#,则该节点为空
ElemType e;
cin>>e;
if(e=='#') t=nullptr;
else{
t=new BiNode;
t->data=e;
//分别创建左右子树
createNode(t->lchild);
createNode(t->rchild);
}
}
void BiTree::createBiTree(){
createNode(root);
}
3.删除二叉树
void BiTree::deleteNode(BiNode* t){
if(t){
deleteNode(t->lchild); //递归删除左子树
deleteNode(t->rchild); //递归删除右子树
delete t; //删除根节点
}
}
void BiTree::deleteBiTree(){
if(root!=nullptr){
deleteNode(root);
}
}
4.计算二叉树的高度
int BiTree::height(BiNode* t){
int lheight=0, rheight=0;
if(t==nullptr) return 0;
lheight=height(t->lchild);
rheight=height(t->rchild);
return lheight>=rheight?lheight+1:rheight+1;
}
int BiTree::heightOfBiTree(){
return height(root);
}
5.计算二叉树的叶子结点数
1.递归
int BiTree::numOfLeaf(BiNode *t){
int num_l_leaf, num_r_leaf;
if(t==nullptr){
return 0;
}
//分别计算左右子树的叶子结点数
num_l_leaf=numOfLeaf(t->lchild);
num_r_leaf=numOfLeaf(t->rchild);
if(num_l_leaf+num_r_leaf==0){
//若该结点是叶子结点,返回1
return 1;
}
else{
//若该结点不是叶子结点,则返回该结点的叶子结点数
return num_l_leaf+num_r_leaf;
}
}
int BiTree::numOfBTLeaf(){
return numOfLeaf(root);
}
2.非递归
int BiTree::numOfBTLeaf_NonRec(){
int num=0;
BiNode *p=root;
stack<BiNode*> ss;
while(p||!ss.empty()){
while(p){
ss.push(p);
p=p->lchild;
}
if(!ss.empty()){
p=ss.top();
ss.pop();
if(p->lchild==nullptr&&p->rchild==nullptr) num++;
p=p->rchild;
}
}
return num;
}
6.计算二叉树结点数
int BiTree::numOfNodes(BiNode *t){
if(t==nullptr) return 0;
return numOfNodes(t->lchild)+numOfNodes(t->rchild)+1;
}
int BiTree::numOfBTNodes(){
return numOfNodes(root);
}
7.搜索二叉树中数据为e
的结点
BiNode* BiTree::search(BiNode *t, ElemType e){
BiNode *temp=nullptr;
if(t==nullptr) return nullptr;
if(t->data==e) return t;
temp=search(t->lchild,e);
//如果temp不为null,说明在左子树中已经找到目标结点
//于是只要返回temp即可
//若没有在左子树中找到目标结点,则开始遍历右子树
if(temp!=nullptr) return temp;
else return search(t->rchild,e);
}
BiNode* BiTree::searchBTNode(ElemType e){
return search(root, e);
}
8.计算二叉树中度为2的结点数
int BiTree::numOfBTNodesDegree2(){
//计算二叉树度为2的结点数
//我们利用公式n0=n2+1,因此只需要找到叶子结点数-1即可
if(root==nullptr) return 0;
return numOfBTLeaf()-1;
}
9.先序遍历二叉树
1.递归
void BiTree::preOrder(BiNode *t){
//先序遍历二叉树
if(t){
cout<<t->data<<' ';
preOrder(t->lchild);
preOrder(t->rchild);
}
}
void BiTree::preOrderBTTraverse(){
//先序遍历二叉树
preOrder(root);
cout<<'\n';
}
2.非递归
void BiTree::preOrderBTTraverse_NonRec(){
BiNode *p=root;
stack<BiNode*> ss;
//若p为空或栈为空,遍历结束
//先序遍历顺序:根-左-右
while(p||!ss.empty()){
if(p){
cout<<p->data<<' ';
ss.push(p);
p=p->lchild;
}
else{
p=ss.top();
ss.pop();
p=p->rchild;
}
}
cout<<'\n';
}
10.中序遍历二叉树
1.递归
void BiTree::inOrder(BiNode *t){
if(t){
inOrder(t->lchild);
cout<<t->data<<' ';
inOrder(t->rchild);
}
}
void BiTree::inOrderBTTraverse(){
//中序遍历二叉树
inOrder(root);
cout<<'\n';
}
2.非递归
void BiTree::inOrderBTTraverse_NonRec(){
BiNode *p=root;
stack<BiNode*> ss;
//中序遍历顺序:左-根-右
while(p||!ss.empty()){
if(p){
ss.push(p);
p=p->lchild;
}
else{
p=ss.top();
ss.pop();
cout<<p->data<<' ';
p=p->rchild;
}
}
cout<<'\n';
}
11.后序遍历二叉树
1.递归
void BiTree::postOrder(BiNode *t){
if(t){
postOrder(t->lchild);
postOrder(t->rchild);
cout<<t->data<<' ';
}
}
void BiTree::postOrderBTTraverse(){
//后序遍历二叉树
postOrder(root);
cout<<'\n';
}
2.非递归
void BiTree::postOrderBTTraverse_NonRec(){
BiNode *p=root;
stack<BiNode*> ss;
//后序遍历顺序:左-右-根
while(p||!ss.empty()){
if(p){
p->pushNum++;
ss.push(p);
p=p->lchild;
}
else{
p=ss.top();
ss.pop();
//如果p入过一次栈,那么将其二次入栈
if(p->pushNum==1){
p->pushNum++;
ss.push(p);
p=p->rchild;
}
else{
//最后输出根结点的数据
cout<<p->data<<' ';
//注意,访问完该结点,由于要访问该结点双亲结点的右-根,故将其设为null
p=nullptr;
}
}
}
cout<<'\n';
}
12.二叉树的层次遍历
void BiTree::levelOrderTraverse(){
BiNode *p=root;
queue<BiNode*>lq;
if(p) lq.push(p);
while(!lq.empty()){
p=lq.front();
lq.pop();
cout<<p->data<<' ';
if(p->lchild) lq.push(p->lchild);
if(p->rchild) lq.push(p->rchild);
}
cout<<'\n';
}
13.交换二叉树的左右子树
void Solution::exchangeSubTree(BiNode *&t){
//递归:交换二叉树的左右子树
BiNode *temp;
if(t){
//交换t结点的左右结点
temp=t->lchild;
t->lchild=t->rchild;
t->rchild=temp;
//继续交换t结点左右子结点各自的左右结点
exchangeSubTree(t->lchild);
exchangeSubTree(t->rchild);
}
}
14.判断两棵二叉树是否相似
bool Solution::isSimilar(BiNode *a, BiNode *b){
if(a==nullptr&&b==nullptr) return true;
if(a==nullptr||b==nullptr) return false;
else return isSimilar(a->lchild, b->lchild) && isSimilar(a->rchild, b->rchild);
}
15.拷贝二叉树
1.递归
void Solution::copyBiNode(BiNode *t, BiNode *&p){
if(t==nullptr){
p=nullptr;
return;
}
p=new BiNode;
p->data=t->data;
copyBiNode(t->lchild,p->lchild);
copyBiNode(t->rchild,p->rchild);
}
void Solution::copyBiTree1(BiTree *t, BiTree *&p){
//利用递归算法将二叉树t拷贝至p
if(t==nullptr) {
return;
}
p=new BiTree();
copyBiNode(t->root,p->root);
}
2.非递归
void Solution::copyBiTree2(BiTree *t, BiTree *&p){
//通过遍历二叉树并将t拷贝至p
p=new BiTree();
BiNode *nt=t->root;
BiNode *newp;
if(!t||!t->root) return;
stack<BiNode*> stack_t, stack_p;
//若目标二叉树为空,则无需拷贝
if(nt==nullptr) return;
//新建头结点并初始化
newp=new BiNode;
newp->data=nt->data;
newp->lchild=newp->rchild=nullptr;
//将头结点入栈
stack_t.push(nt);
stack_p.push(newp);
while(!stack_t.empty()){
//取出头结点
BiNode* nt=stack_t.top();
BiNode* np=stack_p.top();
stack_t.pop();
stack_p.pop();
//若该结点的右孩子不为空,则将右孩子入栈并将该结点拷贝
if(nt->rchild!=nullptr){
stack_t.push(nt->rchild);
np->rchild=new BiNode;
np->rchild->data=nt->rchild->data;
np->rchild->lchild=np->rchild->rchild=nullptr;
stack_p.push(np->rchild);
}
//若该结点的左孩子不为空,则将左孩子入栈并将该结点拷贝
if(nt->lchild!=nullptr){
stack_t.push(nt->lchild);
np->lchild=new BiNode;
np->lchild->data=nt->lchild->data;
np->lchild->lchild=np->lchild->rchild=nullptr;
stack_p.push(np->lchild);
}
}
p->root=newp;
}
main函数
int main()
{
BiTree* b=new BiTree();
b->createBiTree();
cout<<"对二叉树b先序、中序、后序递归遍历"<<'\n';
b->preOrderBTTraverse();
b->inOrderBTTraverse();
b->postOrderBTTraverse();
cout<<'\n';
cout<<"对二叉树b先序、中序、后序非递归遍历"<<'\n';
b->preOrderBTTraverse_NonRec();
b->inOrderBTTraverse_NonRec();
b->postOrderBTTraverse_NonRec();
cout<<'\n';
cout<<"对二叉树b层次遍历"<<'\n';
b->levelOrderTraverse();
return 0;
}
一些测试用例
测试用例1
A
B
E
#
#
C
D
#
#
#
F
#
G
H
#
I
#
#
J
#
#
测试用例2
A
B
D
H
#
#
I
#
#
E
#
#
C
F
#
#
G
#
#
运行结果:
测试用例1
对二叉树b先序、中序、后序递归遍历
A B E C D F G H I J
E B D C A F H I G J
E D C B I H J G F A
对二叉树b先序、中序、后序非递归遍历
A B E C D F G H I J
E B D C A F H I G J
E D C B I H J G F A
对二叉树b层次遍历
A B F E C G D H J I
测试用例2
对二叉树b先序、中序、后序递归遍历
A B D H I E C F G
H D I B E A F C G
H I D E B F G C A
对二叉树b先序、中序、后序非递归遍历
A B D H I E C F G
H D I B E A F C G
H I D E B F G C A
对二叉树b层次遍历
A B C D E F G H I
本文完