树形结构,主要弄懂计算树的深度、结点数的计算,还要弄清一些容易混淆的概念如深度与高度,树和森林与二叉树的转换等,因为在我刚开始学习时找到的教学都是概念为主,没有足够的图来辅助理解,所以今天主要整理树和二叉树的概念及遍历代码,前面介绍到的广义表也可以用二叉树表示。
树
叶子结点
没有子结点的结点称为叶子结点,如图中的3,5,6,7
树的度
结点的分支数称为该结点的度,如下图结点1的度为3,结点2的度为2. 树的度是所有结点中最大的度,这棵树的度为3
树的深度
从上往下,以根节点为第一层,往下能达到的最大层数称为树的深度,图片中树的深度为4,结点5的深度为3
树的高度
从下往上,叶子结点为第一层,最大层数称为树的高度。但相同深度的结点,其高度不一定相同。如图中结点5的深度为3,而高度为2
二叉树
普通二叉树:
在第 i 层至多有 2 i-1 个结点,至少有 1 个结点
深度为h的二叉树,至多有 2h - 1 个结点 ,至少有h个结点。
若有n0个叶子结点,n1个度为1的结点,n2个度为2的结点,则n0 = n2+1,
总结点数N = n0+n1+n2 或 N = n1+2n2+1
因为二叉树的左右结点不一样,因为结点放在不同位置的时候二叉树形态不同,3个结点便能有以下5中形态的二叉树
三种遍历方法
前序遍历:从根结点开始,遍历左孩子再遍历右孩子。若孩子是子树,则重复以上步骤。如图的遍历序列为1 2 4 3 6 8 9 7
中序遍历:从最左侧的结点开始,依次遍历左孩子、根结点、右孩子。若孩子是子树,则重复步骤。如图中序序列为4 2 1 8 6 9 3 7
后序遍历:从最左侧的结点开始,依次遍历左孩子、右孩子、根结点。若孩子是子树。重复步骤。图中后序序列为4 2 8 9 6 7 3 1
#include<stdlib.h>
#include<stdio.h>
typedef struct Bitree{//定义树的结构体
char data;
Bitree *lchild;
Bitree *lchild;
}
Bitree* create(){//创建树
char ch;
Bitree *T;
scanf("%c",&ch);
if(ch == '#')//若输入#,则该结点为空
T = NULL;
else{//先序遍历创建
T = (Bitree*)malloc(sizeof(Bitree));
T->data = ch;//将元素赋值给数据域
T->lchild = create();//左右子树递归上述操作
T->rchild = create();
}
return T;
}
void Insert(Bitree *T,char x){//二叉树的插入
if(T == NULL){//若树为空,直接插入
T = (Bitree*)malloc(sizeof(Bitree));
T->data = x;
}
else if(x<T->data){//若插入的数比根结点小,则插入左子树
if(T->lchild!=NULL)//若非空,则递归调用函数
Insert(T->lchild,x);
else//若左子树空,直接插入
T->lchild->data = x;
}
else if(x>T->data){//比根结点大,插入右子树
if(T->rchild!=NULL)
Insert(T->rchild,x);
else
T->rchild->data = x;
}
}
void pre(Bitree *T){//先序遍历打印结点
if(T == NULL)
printf("NULL\n");
else{
printf("%c",T->data);
pre(T->lchild);
pre(T->rchild);
}
}
void mid(Bitree *T){//中序遍历打印结点
if(T == NULL)
printf("NULL\n");
else{
printf("%c",T->data);
mid(T->lchild);
mid(T->rchild);
}
}
void post(Bitree *T){//后序遍历打印结点
if(T == NULL)
printf("NULL\n");
else{
printf("%c",T->data);
ppst(T->lchild);
post(T->rchild);
}
}
前序遍历是 根、左、右
中序遍历是 左、根、右
后序遍历是 左、右、根
易得:
1.若前序和中序序列相同,则该二叉树是所有结点只有右子树;
2.若中序和后序序列相同,则所有结点只有左子树;
3.若前、中、后序都相同,则该二叉树只有根节点;
4.若前序和后序遍历正好相反,则为空或只有一个结点。
5.知道中序序列后,给出其他任意一种序列都能画出完整的二叉树
二叉线索树
二叉线索树利用了空指针域,提升了遍历速度,但插入和删除的难度加大。假设有n个结点,必有n+1个空指针域。二叉线索树通过利用这些空指针域指向该结点的前驱和后继。以下图的二叉树为例子,简单介绍中序和后序线索二叉树。
如图可得二叉树的遍历序列:
中序:5 2 1 7 4 3
后序:5 2 7 3 4 1
结点5 7 3是叶子结点,因此其左右指针域皆为空。左孩子为空,则其指向该遍历顺序的前驱 , 右孩子为空,则指向该遍历的后继。无前驱或后继则指向空。
中序线索树
后序线索树
完全二叉树
一颗二叉树,从上到下,从左到右对结点进行编号,如果每个结点的编号都与满二叉树的该位置的编号相同,则其为完全二叉树。就是说,如果一个结点,它没有左子树,那它一定没有右子树。
深度为h的完全二叉树最多有2h - 1个结点,最少有2h-1个结点。