二叉树
概念
树是一个拥有层次关系N(N>0)的有限集合,如果N为0(即层数为0)则为空树,N>0时为非空树
对于非空二叉树,是由一个根节点加两个不相交的子集节点组成,而子节点又可以分别向下延伸出两个不相交的子节点
注:对于根节点有且只有一个,其余都不为根节点,一个节点延伸出的两个节点分别称为左子树和右子树
对于二叉树还有几个概念
- 节点的度:一个节点拥有子树的数量
- 树的度:树中所有节点的度的最大值
- 层:从根节点开始记为1,那么第N个节点处于第N层,其子节点处于N+1层
- 树的深度:也称为树的高度,树中所有节点的层次最大值称为树的深度
- 分支节点:度不为0的节点
- 叶子节点:没有子节点,即度为0的节点
二叉树主要分为满二叉树和完全二叉树
满二叉树:如果一棵二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树
即除了叶子节点,其余分支节点度都为2,都有两个子树
完全二叉树:深度为k,有n个节点的二叉树当且仅当其每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树
完全二叉树与满二叉树的区别就是缺少了右边的叶子节点
二叉树的性质
- 二叉树的第N层上至多有2N-1(N≥1)个节点
- 深度为N的二叉树中至多含有2N-1个节点
- 若在任意一棵二叉树中,有N0个叶子节点,有N2个度为2的节点,则必有N0=N2+1
- 具有n个节点的满二叉树深为log2N+1。
- 若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤N),那么,对于编号为i(i≥1)的节点当i=1时,该节点为根节点,当i>1时,该节点的双亲节点的编号为i/2,若2i≤N,则有编号为2i的左节点,否则没有左节点若2i+1≤n,则有编号为2i+1的右节点,否则没有右节点
二叉树的储存方式
分为链式储存和顺序储存
链式储存
如其名,像链表的储存方式
用两个指针分别指向两个子树,将他们串起来
代码如下
struct tree
{
int val;
tree *left;
tree *right;
};
顺序储存
顺序储存是使用数组来储存
将下标0赋给根节点,那么它的左子树节点下标为1,右子树节点的下标为2
一个节点的下标为i,那么其左子节点下标为2*i+1,右子节点为2*i+2
二叉树的遍历方式
- 深度优先遍历:先往深走,遇到叶子节点再往回走。
- 广度优先遍历:一层一层的去遍历。
深度遍历又分为先序遍历,中序遍历,后序遍历
- 先序遍历:先遍历中间节点,再遍历左右节点
- 中序遍历:先遍历左节点,再遍历中右节点
- 后序遍历:先遍历左右节点,再遍历中节点
所以先中后指的是中间节点的遍历顺序
代码实现
void find(tree* root)//先序遍历
{
if(root==NULL)
return;
cout<<root->val<<" ";//访问根节点
find(root->left);//遍历左树
find(root->right);//遍历右树
}
void find(tree* root)//中序遍历
{
if(root==NULL)//空树则返回
return;
find(root->left);//遍历左树
cout<<root->val<<" ";//访问根节点
find(root->right);//遍历右树
}
void find(tree* root)//后序遍历
{
if(root==NULL)
return;
find(root->left);//遍历左树
find(root->right);//遍历右树
cout<<root->val<<" ";//访问根节点
}
层序遍历
层次遍历是指从二叉树的根节点开始,按从上到下,从左到右的顺序遍历,类似于数组的顺序遍历
使用队列来实现
void find2(tree* root) {
if(root==NULL)
return;
queue<tree*>q;
q.push(root);
while (!q.empty()) {
Tree* node=q.front();
q.pop();
cout<<node->val<<" "; // 访问当前节点
if (node->left!=NULL)
q.push(node->left);
if (node>right!=NULL)
q.push(node->right);// 将当前节点的左右子节点加入队列
}
}