一、二叉树定义:
二叉树是n个结点的有限集合,该集合或者为空(空二叉树)、或者由一个根结点及两个不相交的、被分别称为左子树和右子树的二叉树组成
特殊二叉树:
(1)斜树:所有的结点都只有左子树的二叉树叫左斜树。所有的结点都只有右子树的二叉树,叫右斜树,两者统称为斜树
(2)满二叉树:在一棵二叉树中,如果所有分支结点都存在左子树和右子树,并且所有叶子都在同一层上,这样的二叉树叫做满二叉树
(3)完全二叉树:对一棵具有n个结点的二叉树按层序编号,如果编号为i(1≤i≤n)的结点与同样深度的满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树
满二叉树一定是完全二叉树,但是完全二叉树不一定是满二叉树
二、二叉树的性质:
(1)在二叉树的第i层上至多有个结点(i>=1)
(2)深度为k的二叉树至多有个结点
(3)对于任何一个二叉树T,如果其终端结点数为,度为2的结点数为,则 =
(4)具有n个结点的完全二叉树的深度为
(5)对于一棵有n个结点的完全二叉树(其深度为),其结点按层序编号,每层从左到右,对任意一个结点i(1<=i<=n)有:
<1>如果i=1,则结点i是二叉树的根,无双亲;如果I > 1,则其双亲结点是[i / 2]
<2>如果2i > n,则结点i无左孩子(结点i为叶子节点);否则其左孩子是结点2i
<3>如果2i + 1> n,则结点无右孩子;否则其右孩子是2i + 1
三、二叉树的存储结构:
由于二叉树的特殊性,我们可以用顺序存储结构来实现,就是用一维数组来存储二叉树的结点,并且结点的存储位置,也就是数组的下标要能体现结点之间的逻辑关系。
对一般二叉树,层序编号不能反映逻辑关系,但是可以将其按完全二叉树编号,只不过把不存在的结点设置为“^”,但是考虑一种极端情况,一棵深度为k的右斜树,它只有k个结点,但是要分配2𝑘−1个结点,显然是对空间的浪费。
所以,顺序存储结构一般只适用于完全二叉树。
二叉树的每个结点最多有两个孩子,所以设计一个数据域和两个指针域是比较合适的,我们称这样的链表叫做二叉链表
//二叉树的二叉链表结点结构定义
typedef char ElemType;
typedef struct BiTNode //结点结构
{
ElemType data;
struct BiTNode* lchild; //左孩子指针
struct BiTNode* rchild; //右孩子指针
}BiTNode,*BiTree;
四、遍历二叉树:
(1)前序遍历:先访问根结点,然后前序遍历左子树,再前序遍历右子树
//二叉树的前序遍历递归算法
void PreOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
printf("%c ", T->data); //显示结点数据
PreOrderTraverse(T->lchild); //遍历左子树
PreOrderTraverse(T->rchild); //遍历右子树
}
(2)中序遍历:从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后访问根结点,最后中序遍历右子树
//二叉树的中序遍历递归算法
void InOrderTraverse(BiTree T)
{
if (T == NULL)
{
return;
}
InOrderTraverse(T->lchild);
printf("%c ", T->data);
InOrderTraverse(T->rchild);
}
(3)后序遍历:从左到右先叶子后结点的方式遍历访问左右子树,最后访问根结点
//二叉树的后续遍历递归算法
void PostOrderTraverse(BiTNode* T)
{
if (T == NULL)
{
return;
}
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c ", T->data);
}
(4)层序遍历:从根结点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序对结点逐个访问
对于以上二叉树:
前序遍历:ABDEHCFG
中序遍历:DBHEAFCG
后序遍历:DHEBFGCA
层序遍历:ABCDEFGH
二叉树遍历的性质:
已知前序遍历序列和中序遍历序列,可以唯一确定一棵二叉树
已知后序遍历序列和中序遍历序列,可以唯一确定一棵二叉树
五、二叉树的建立:
如果我们要建立左图这样的树,为了能让每个结点确认是否有左右孩子,我们对它进行了扩展,如右图所示,也就是将二叉树中每个结点的空指针引出一个虚结点,其值为#。我们称这种处理后的二叉树为原二叉树的扩展二叉树。
扩展二叉树就可以做到一个遍历序列确定一棵二叉树,如上图前序遍历序列就是:AB#D#C##
假设二叉树的结点均是一个字符
//按前序输入二叉树中结点的值创建二叉树
void CreateBiTree(BiTree* T)
{
ElemType ch;
scanf("%c", &ch);
if (ch == '#')
*T = NULL;
else
{
*T = (BiTree)malloc(sizeof(BiTNode));
if (!*T)
exit(1);
(*T)->data = ch;
CreateBiTree(&(*T)->lchild);
CreateBiTree(&(*T)->rchild);
}
}