一般二叉树
什么是二叉树?
树是常用的一种非线性数据结构。
树有很多衍生分类,其中,二叉树便是最为常见的一种。
二叉树的定义是以递归形式给出的:一棵二叉树是结点的一个有限集合,该集合可能为空,或则是由一个根节点加上两棵分别称为左子树、右子树的、互不相交的二叉树组成。
二叉树的特点是每个结点最多有两个子女,分别称为该节点的左子树和右子树。
在二叉树中不存在度大于2的结点,并且二叉树的字子树有左子树、右子树之分,其子树的次序不能颠倒。
二叉树是分支数最大不超过2的有根有序树。
二叉树的性质
二叉树的基本操作?
二叉树的基本操作有:
- 创建二叉树
- 前序遍历
- 中序遍历
- 后序遍历
- 层序遍历
- 求结点个数
- 求二叉树的深度
- 销毁二叉树
二叉树相关算法的基本模式
由于树本身的定义就是递归定义的,
所以二叉树的基本操作多半基于递归思想实现。
二叉树结点结构体的设计
//结点结构体的定义
struct BiNode
{
/* data */
int data;
BiNode *lchild; //左孩子
BiNode *rchild; //右孩子
};
二叉树类的设计
class BiTree
{
private:
/* data */
int IsRoot=0;
BiNode *Creat(); //构造函数调用
void Release(BiNode *bt); //析构函数调用
void PreOrder(BiNode *bt); //前序遍历函数调用
void InOrder(BiNode *bt); //中序遍历函数调用
void PostOrder(BiNode *bt); //后序遍历函数调用过程
int Size(BiNode *bt); //获取结点个数调用过程
int Height(BiNode *bt); //获取二叉树高度的调用过程
BiNode *root; //指向根节点的头指针
public:
BiTree(){this->root=Creat();} //构造函数 建立一棵二叉树
~BiTree(){Release(root);} //析构函数,释放各结点的存储空间
void PreOrder(){PreOrder(root);} //前序遍历二叉树
void InOrder(){InOrder(root);} //中序遍历二叉树
void PostOrder(){PostOrder(root);} //后序遍历二叉树
int Size(){return Size(root);} //获取二叉树结点个数
int Height(){return Height(root);} //获取二叉树的高度(深度)
};
二叉树类的实现
创建二叉树
我们采用从键盘输入的方式进行创建,当输入0时表示该结点为空。
BiNode* BiTree::Creat()
{
//可以采用广义表的方法去建立二叉树
// if(IsRoot==0)
// {
// cout<<"请输入根结点数据域(0表示空)"
// }
BiNode *bt;
int da; //临时变量
cout<<"请输入该结点数据域(0表示空):";
cin>>da;
if(da==0)
{
bt=nullptr;
}
else
{
bt=new BiNode;
bt->data=da;
bt->lchild=Creat(); //递归调用创建结点方法
bt->rchild=Creat(); //递归调用创建结点方法
}
return bt; //返回总树及每一棵子树的根节点root
}
销毁二叉树
void BiTree::Release(BiNode *bt)
{
//析构函数的调用过程
cout<<"析构"<<endl;
//和后续遍历的思想一致
//左子树 右子树 根节点
//递归终止条件
if(bt==nullptr)
{
return;
}
else
{
Release(bt->lchild); //递归调用释放左子树
Release(bt->rchild); //递归调用释放右子树
delete bt;
}
cout<<"析构成功"<<endl;
}
前序遍历
void BiTree::PreOrder(BiNode *bt)
{
//递归调用的终止条件
if(bt==nullptr)
{
return;
}
else
{
//前序遍历: 根节点 左子树 右子树
cout<<bt->data<<" "; //输出数据域
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
中序遍历
void BiTree::InOrder(BiNode *bt)
{
//中序遍历
if(bt==nullptr)
{
return;
}
else
{
//中序遍历: 左子树 根节点 右子树
InOrder(bt->lchild);
cout<<bt->data<<" ";
InOrder(bt->rchild);
}
}
后序遍历
void BiTree::PostOrder(BiNode *bt)
{
//后序遍历
if(bt==nullptr)
{
return;
}
else
{
//后序遍历:左子树 右子树 根节点
PostOrder(bt->lchild);
PostOrder(bt->rchild);
cout<<bt->data<<" ";
}
}
求结点个数
int BiTree::Size(BiNode *bt)
{
if(bt==nullptr)
{
return 0;
}
return 1+Size(bt->lchild)+Size(bt->rchild);
}
求二叉树的深度
int BiTree::Height(BiNode *bt)
{
//求二叉树的高度(深度)
if(bt==nullptr)
{
return 0;
}
int i=Height(bt->lchild);
int j=Height(bt->rchild);
return i<j ? j+1 : i+1;
}
二叉树测试
#include<iostream>
#include"BiTree.h"
using namespace std;
int main()
{
cout<<"基于链式存储结构的二叉树"<<endl;
BiTree b1;
cout<<"前序遍历:";
b1.PreOrder();
cout<<endl;
cout<<"中序遍历:";
b1.InOrder();
cout<<endl;
cout<<"后序遍历:";
b1.PostOrder();
cout<<endl;
cout<<"当前二叉树共有"<<b1.Size()<<"个结点"<<endl;
cout<<"当前二叉树的高度(深度)为"<<b1.Height()<<endl;
system("pause");
return 0;
}
完整代码
BiTree.h
/*
手撕二叉树
树结构本身是递归定义的
在这里,我们整个数据结构的定义和实现也大多基于递归
*/
#include<iostream>
using namespace std;
//结点结构体的定义
struct BiNode
{
/* data */
int data;
BiNode *lchild; //左孩子
BiNode *rchild; //右孩子
};
class BiTree
{
private:
/* data */
int IsRoot=0;
BiNode *Creat(); //构造函数调用
void Release(BiNode *bt); //析构函数调用
void PreOrder(BiNode *bt); //前序遍历函数调用
void InOrder(BiNode *bt); //中序遍历函数调用
void PostOrder(BiNode *bt); //后序遍历函数调用过程
int Size(BiNode *bt); //获取结点个数调用过程
int Height(BiNode *bt); //获取二叉树高度的调用过程
BiNode *root; //指向根节点的头指针
public:
BiTree(){this->root=Creat();} //构造函数 建立一棵二叉树
~BiTree(){Release(root);} //析构函数,释放各结点的存储空间
void PreOrder(){PreOrder(root);} //前序遍历二叉树
void InOrder(){InOrder(root);} //中序遍历二叉树
void PostOrder(){PostOrder(root);} //后序遍历二叉树
int Size(){return Size(root);} //获取二叉树结点个数
int Height(){return Height(root);} //获取二叉树的高度(深度)
};
BiTree.cpp
#include"BiTree.h"
BiNode* BiTree::Creat()
{
//可以采用广义表的方法去建立二叉树
// if(IsRoot==0)
// {
// cout<<"请输入根结点数据域(0表示空)"
// }
BiNode *bt;
int da; //临时变量
cout<<"请输入该结点数据域(0表示空):";
cin>>da;
if(da==0)
{
bt=nullptr;
}
else
{
bt=new BiNode;
bt->data=da;
bt->lchild=Creat(); //递归调用创建结点方法
bt->rchild=Creat(); //递归调用创建结点方法
}
return bt; //返回总树及每一棵子树的根节点root
}
void BiTree::Release(BiNode *bt)
{
//析构函数的调用过程
cout<<"析构"<<endl;
//和后续遍历的思想一致
//左子树 右子树 根节点
//递归终止条件
if(bt==nullptr)
{
return;
}
else
{
Release(bt->lchild); //递归调用释放左子树
Release(bt->rchild); //递归调用释放右子树
delete bt;
}
cout<<"析构成功"<<endl;
}
void BiTree::PreOrder(BiNode *bt)
{
//递归调用的终止条件
if(bt==nullptr)
{
return;
}
else
{
//前序遍历: 根节点 左子树 右子树
cout<<bt->data<<" "; //输出数据域
PreOrder(bt->lchild);
PreOrder(bt->rchild);
}
}
void BiTree::InOrder(BiNode *bt)
{
//中序遍历
if(bt==nullptr)
{
return;
}
else
{
//中序遍历: 左子树 根节点 右子树
InOrder(bt->lchild);
cout<<bt->data<<" ";
InOrder(bt->rchild);
}
}
void BiTree::PostOrder(BiNode *bt)
{
//后序遍历
if(bt==nullptr)
{
return;
}
else
{
//后序遍历:左子树 右子树 根节点
PostOrder(bt->lchild);
PostOrder(bt->rchild);
cout<<bt->data<<" ";
}
}
int BiTree::Size(BiNode *bt)
{
if(bt==nullptr)
{
return 0;
}
return 1+Size(bt->lchild)+Size(bt->rchild);
}
int BiTree::Height(BiNode *bt)
{
//求二叉树的高度(深度)
if(bt==nullptr)
{
return 0;
}
int i=Height(bt->lchild);
int j=Height(bt->rchild);
return i<j ? j+1 : i+1;
}
main.cpp
#include<iostream>
#include"BiTree.h"
using namespace std;
int main()
{
cout<<"基于链式存储结构的二叉树"<<endl;
BiTree b1;
cout<<"前序遍历:";
b1.PreOrder();
cout<<endl;
cout<<"中序遍历:";
b1.InOrder();
cout<<endl;
cout<<"后序遍历:";
b1.PostOrder();
cout<<endl;
cout<<"当前二叉树共有"<<b1.Size()<<"个结点"<<endl;
cout<<"当前二叉树的高度(深度)为"<<b1.Height()<<endl;
system("pause");
return 0;
}
思考
如何优化二叉树的创建过程?
前/中/后序遍历如何通过非递归方式实现?
层序遍历如何实现?基于队列?
用code改变世界的创造者们,节日快乐!