树形结构——二叉树
二叉树顾名思义就是有两个分支的树,用数据结构的概念翻译过来就是每个结点最多只有两个孩子(left & right)即最多只有两棵子树,每个结点的度最大为2,不存在大于2的结点,它是一颗有序树。
####概念
一棵二叉树是节点的有限集合,该集合或者为空,或者由一个根结点加上两棵分别称为左子树和右子树的二叉树组成。
这个概念想到了什么呢?没错,是递归,二叉树就是由递归来构建的。
两种类型的二叉树
- 满二叉树:在一棵二叉树中所有结点都存在左子树和右子树,即除了叶子结点外每个节点的度为2 并且所有叶子结点都在同一层上。
- 完全二叉树:有N个结点的二叉树与满二叉树的前N个结点的结构相同。
二叉树的性质
- 1,若规定根结点的层数为0,则一棵非空二叉树的第n层最多有2的i次方(i>0)个结点
- 2,若规定只有根结点的二叉树的深度为0,则深度为K的二叉树的最大节点数为 $ 2^ ( k + 1 ) - 1 $
- 3,对任何一棵二叉树都有非叶节点的个数加1等于叶节点数。
- 4,具有n个结点的完全二叉树的深度k为大于或等于lb(n+1)-1的最小整数
- 5,对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始 编号,则对于序号为i的结点有:
- a:如果i>0,则序号为i结点的双亲结点的序号为(i-1)/2;如果i=0,则序号为i的结 点为根节点,无双亲结点
- b:如果2i+1<n,则序号为i的结点的左孩子结点的序号为2i+1;如果2i+1>=n,则序 号为i结点无右孩子结点
- c:如果2i+2<n,则序号为i结点的右孩子结点的序号为2i+2;如果2i+2>=n,则序号 为i结点无右孩子结点
二叉树的存储结构
二叉树的存储结构主要有三种:
- 顺序存储
- 式存储
- 仿真指针(静态链表)存储结构。
二叉树的基本操作
创建一棵二叉树
说到创建一棵二叉树就不得不说二叉树的遍历,
遵循某种次序,遍历二叉树中的所有节点,使得每个结点被访问一次,而且仅访问一次。
“访问”:即对结点施行某些操作。若规定VLR分别代表:访问根节点、遍历二叉树的左子树、遍历二叉树的由子树,则共有6中组合:VLR、LVR、LRV、RLV、RVL、VRL。
- 前序:VLR, 前序镜像:RLV
- 中序:LVR, 中序镜像:RVL
- 后续:LRV, 后序镜像:VRL
废话不多说,直接来上代码:
这段代码是用模板类来实现的,本来想着用多文件组织的方式来贴这段代码出来,这样看起来更加明了,结果却不是想象的那样,头文件是没问题,源文件底下全报红,后来一查,模板类不能实现分离编译,模板类最好是声明和定义写在一起,以后可不能犯这样的错误了。
下面来看代码:
template <class T>
struct BinaryTreeNode // 结点
{
BinaryTreeNode(T data)
: _pLeft(NULL)
, _pRight(NULL)
, _data(data)
{}
BinaryTreeNode* _pLeft;
BinaryTreeNode* _pRight;
T _data;
};
template <class T>
class BinaryTree
{
public:
BinaryTree()
{}
BinaryTree(T array[], size_t size)
{
size_t index = 0;
CreateBinaryTree(_pRoot, array, size, index);
}
BinaryTree(const BinaryTree& bt)
{
_pRoot = CopyTree(bt._pRoot);
}
BinaryTree& operator=(const BinaryTree<T>& bt)
{
if (this != &bt)
{
if (_pRoot != NULL)
{
DestoryBinaryTree(_pRoot);
}
_pRoot = CopyTree(bt._pRoot);
}
return *this;
}
~BinaryTree()
{
DestoryBinaryTree(_pRoot);
}
v