二叉树
二叉树是重要的数据结构,在学习中以及考试、面试中不可避免的考点,现在我就把有关二叉树的操作用C++总结 一下,可能有些同学使用的是C语言,但是无论C语言还是c++,对于二叉树的操作方法都是一样的,之后,我也会抽空给出C语言的实现。
本次实现是在vs2008的一个集成开发环境,为了增强代码的复用性,此次编写使用了模版,关于模版可以参考的我的另外一篇博客:http://blog.csdn.net/dy_1024/article/details/78643644,如果大家在使用的时候,不实用模版,只需把代码中的模版类型T,换成你需要的类型即可。
首先我们用结构体给出二叉树结点的结构:
template//如果大家不使用模版的话,把这行代码去掉,将结构体中的T该成你需要的类型即可
struct BinTreeNode{
BinTreeNode(const T& data):_left(NULL),_right(NULL),_data(data){}//二叉树结点的构造函数,方便之后给出新结点
BinTreeNode* _right;//右子树
BinTreeNode* _left;//左子树
T _data;//数据域
};
因为使用c++,所以我们将二叉树封装成一个二叉树类,进行管理,同样使用模版:
template
class BinTree
{
typedef BinTreeNode Node;//将之前的类此重定义,方便以后的使用
typedef Node* PNode;
public:
BinTree():_pRoot(NULL){}
//构造函数里面使用的创建二叉树的函数,
void _CreatBinTree(PNode& pRoot,const T* array,size_t size,size_t& index,const T& invalid)
{
if(index_left,array,size,++index,invalid);
_CreatBinTree(pRoot->_right,array,size,++index,invalid);
}
}
//构造函数,在给构造函数传参的时候,我们定义:char *array ="ABD###CE##F",这是二叉树前序遍历的结果,"#"代表无效值,也就是空子树
BinTree(const T* array,size_t size,const T& invalid)
{
size_t index = 0;
_CreatBinTree(_pRoot,array,size,index,invalid);//我们将二叉树的构造封装成函数,这样结构比较明确
}
//前序遍历
void _PreOrder(PNode pRoot)
{
if(pRoot)
{
cout<_data<<" ";
_PreOrder(pRoot->_left);
_PreOrder(pRoot->_right);
}
}
//中序遍历
void _InOrder(PNode pRoot)
{
if(pRoot)
{
_InOrder(pRoot->_left);
cout<_data<<" ";
_InOrder(pRoot->_right);
}
}
//后续遍历
void _PostOrder(PNode pRoot)
{
if(pRoot)
{
_PostOrder(pRoot->_left);
_PostOrder(pRoot->_right);
cout<_data<<" ";
}
}
//拷贝构造函数里面需要的拷贝函数
PNode _CopyBinTree(PNode pRoot)
{
PNode pNewNode = NULL;
if(pRoot)
{
pNewNode = new Node(pRoot->_data);
pNewNode->_left = _CopyBinTree(pRoot->_left);
pNewNode->_right = _CopyBinTree(pRoot->_right);
}
return pNewNode;
}
BinTree(const BinTree& bt) //拷贝构造函数
{
_pRoot = _CopyBinTree(bt._pRoot);
}
//销毁函数
void _DestoryBinTree(PNode& pRoot)
{
if(pRoot)
{
_DestoryBinTree(pRoot->_left);
_DestoryBinTree(pRoot->_right);
}
delete pRoot;
pRoot = NULL;
}
//赋值运算符重载
BinTree& operator=(const BinTree& bt)
{
//把原有的树销毁掉,在用拷贝函数,拷贝一个新树
_DestoryBinTree(_pRoot);
_pRoot = _CopyBinTree(bt._pRoot);
return *this;
}
//求树的高度
size_t _Height(PNode pRoot)
{
if(NULL == pRoot)
return 0;
if(pRoot->_left == NULL && pRoot->_right == NULL)
{
return 1;
}
size_t left = _Height(pRoot->_left);//将左子树的高度赋值给left
size_t right = _Height(pRoot->_right);//将右子树的高度赋值给right
return left>right?(left+1):(right+1);比较左右子树的大小,大的再加上1,就是树的大小
}
//求按层遍历的个数,思路:当你要求第3层的时候,如果以第二层为根,那么就是求第二层的结点,依次遍历
size_t _GetKLevelNodeCount(PNode pRoot,size_t k)
{
if(k == 0 || NULL == pRoot)return 0;
if(k == 1)return 1;
return _GetKLevelNodeCount(pRoot->_left,k-1)+_GetKLevelNodeCount(pRoot->_right,k-1);
}
//按层遍历,我们使用队列结构保存每次收集的结点,运用队列队头出队尾进的特点,输出每一层的结点
void _LevelOrder(PNode pRoot)
{
PNode pCur = NULL;
queue q;
q.push(pRoot);
while (!q.empty())
{
pCur = q.front();
cout<_data<<" ";
if(pCur->_left)
q.push(pCur->_left);
if(pCur->_right)
q.push(pCur->_right);
q.pop();
}
}
//判断结点是否在树中
bool _IsNodeInBinTree(PNode pRoot,PNode pNode)
{
if(NULL == pRoot || pNode == NULL)
return false;
if(pRoot == pNode)
return true;
bool Isflag = _IsNodeInBinTree(pRoot->_left,pNode);
if(Isflag)
return true;
return _IsNodeInBinTree(pRoot->_right,pNode);
}
//在树种找到一个结点
PNode _Find(PNode pRoot,const T& data)
{
if(NULL == pRoot)
return NULL;
if(pRoot->_data == data)
return pRoot;
PNode pCur = NULL;
if(pCur = _Find(pRoot->_left,data))
return pCur;
return _Find(pRoot->_right,data);
}
//求树的镜像—递归
void _Mirror(PNode pRoot)
{
swap(pRoot->_left, pRoot->_right);//直接交换左右子树里面的地址,那么他的左右子树就交换成功了
if(pRoot->_left)
_Mirror(pRoot->_left);
if(pRoot->_right)
_Mirror(pRoot->_right);
}
//求树得镜像-非递归
void _Mirror_nor(PNode pRoot)
{
if(NULL == pRoot)
return;
queue q;
q.push(pRoot);
while (!q.empty())
{
PNode pCur = q.front();
swap(pCur->_left,pCur->_right);
if(pCur->_left)
q.push(pCur->_left);
if(pCur->_right)
q.push(pCur->_right);
q.pop();
}
}
//判断一棵二叉树是不是一颗完全二叉树,当我们发现一个结点只有左子树,没有右子树的时候,就要开始判断
//下一个结点有没有子树,如果有就不是,如果没有就继续,和层序遍历一样,使用队列结构
bool _IsCompleteBinTree(PNode pRoot){if(NULL == pRoot)return true;queue
限于编者水平,本文文章难免有缺漏之处,欢迎指正
Tip:如需转载,请注明出处