1、树的定义:n个结点的有限集合(n>=0)。
2、树的结点:包含1个数据元素及若干指向其子树的分支。
3、结点的度:结点所拥有的子树数量。
4、树的度:树中所有结点的度的最大值。
5、结点的层次:从根节点开始为第一层
6、树的深度:最大的层次数。
1、二叉树:n个结点的有限集合(n>=0)。特殊在于:n>1时,1个根节点和两棵互不相交的二叉树。
2、满二叉树:①所有的分支结点都有左子树和右子树;②所有的叶子结点都在同一层。
3、完全二叉树:对有n个结点的二叉树按照层序编号,若编号i(1<=i<=n)与同样深度的满二叉树的位置完全相同,则该二叉树为完全二叉树。
4、二叉树的一些性质:
注意:逻辑结构和物理结构的差异。
逻辑结构:分为线性和非线性。(树是非线性结构)
物理结构(存储结构):分为顺序、链式、索引、哈希等,表征数据是如何存储的。(因此树结构也可以有顺序或链式存储结构)
二叉树的顺序存储结构如下:
//二叉树的顺序结构中:一个数组和一个表示位置的结构体。数组存放数据,下标从0开始;位置表征结点的层数和本层序号数。
typedef TElemType SqBiTree[MAX_TREE_SIZE]; //0号单元存储根节点,使用一个数组存放数据
typedef struct
{
int level, order; //结点的层,本层序号(按照满二叉树计算)
}Position;
二叉树的顺序存储,元素是放在数组中,注意点要在根节点与孩子结点的2倍关系、以及结点所在层数和序号之间的计算上。
/************************************************************************/
/* 1.二叉树的顺序结构 */
/************************************************************************/
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100 //存储空间初始分配量
#define MAX_TREE_SIZE 100 //二叉树的最大结点数
typedef int Status;
typedef int TElemType;
typedef TElemType SqBiTree[MAX_TREE_SIZE]; //0号单元存储根节点,使用一个数组存放数据
typedef struct
{
int level, order; //结点的层,本层序号(按照满二叉树计算)
}Position;
TElemType Nil=0; //设整型以0为空
Status visit_SqBiTree(TElemType c)
{
printf("%d ",c);
return OK;
}
//构造空二叉树T。因为T是固定数组,不会改变,因此不需要&
Status InitBiTree(SqBiTree T)
{
int i;
for (i=0;iT[i]=Nil; //初值为空
return OK;
}
//按层序的次序输入二叉树中结点的值,构造顺序存储的二叉树T
Status CreateBiTree(SqBiTree T)
{
int i=0;
printf("请按照层序输入结点的值,0表示空节点,输入999表示结束,结点数<=%d\n",MAX_TREE_SIZE);
while(i<10)
{
T[i]=i+1;
if (i !=0 && T[(i+1)/2-1]==Nil && T[i]!=Nil) //此结点不空,无双亲且不是根
{
printf("出现无双亲的非根结点%d\n",T[i]);
exit(ERROR);
}
i++;
}
while(iT[i]=Nil; //将空值赋给T后面的结点
i++;
}
return OK;
}
#define ClearBiTree InitBiTree //在二叉树的顺序存储结构中,清除和初始化函数一样
/* 初始条件:二叉树T存在*/
/*操作结果:若T为空二叉树,则返回TRUE;否则返回FALSE*/
Status isBiTreeEmpty(SqBiTree T)
{
if (T[0]==Nil) //若根节点为空,则树空
return TRUE;
else
return FALSE;
}
/*初始条件:二叉树T存在。操作结果:返回T的深度*/
int BiTreeDepth(SqBiTree T)
{
int i,j=-1;
for (i=MAX_TREE_SIZE-1; i>=0;i--) //找到最后一个结点
{
if (T[i]!=Nil)
break;
}
i++;
do
{
j++;
} while (i>=powl(2,j)); //计算2的j次幂.pow(x,y):计算x的y次方
return j;
}
/* 初始条件:二叉树T存在*/
/* 操作结果:当T不为空,用e返回T的根,返回OK;否则返回ERROR*/
Status Root(SqBiTree T, TElemType *e)
{
if (isBiTreeEmpty(T)) //先判断是否为空
return ERROR;
else
{
*e =T[0];
return OK;
}
}
/* 初始条件:二叉树T存在,e是T中某个结点*/
/*操作结果:返回处于位置e(层,本层序号)的结点的值*/
TElemType Value(SqBiTree T, Position e)
{
//2的k-1次方是当前层的第一个元素下标,再加上元素在当前层的序列,-1是得到在该层的准确位置,再进行-1是因为数组下标从0开始存数据(T[0]存放根节点数据)
return T[(int)powl(2,e.level-1)+e.order-2];//将层序号转换为在数组中存放的下标
}
/* 初始条件:二叉树T存在,e是T中某个结点的位置*/
/* 操作结果:给处于位置e(层)的结点赋予新值value*/
Status Assign(SqBiTree T, Position e, TElemType value)
{
int i=(int)powl(2,e.level-1)+e.order-2; //将层号转换为矩阵(一位数组)序号
if (value!=Nil && T[(i+1)/2-1]==Nil) //value非空;若双亲为空
return ERROR;
else if (value==Nil && (T[i*2+1]!=Nil || T[i*2+2]!=Nil)) //给存在孩子的双亲赋空
return ERROR;
T[i]=value; //以上两种情况都不是,即给T[i]赋值
return OK;
}
/*初始条件:二叉树T存在,e是T中的某个结点*/
/*操作结果:若e是T的非根节点,则返回它的双亲,否则返回空*/
TElemType Parent(SqBiTree T, TElemType e)
{
//判断是否为空树
if (T[0]==Nil)
return Nil;
for (int i=1; i<=MAX_TREE_SIZE-1; i++)
{
if (T[i]==e) //先找到结点e
{
return T[(i+1)/2-1];
}
}
return Nil; //没找到e
}
/*初始条件:二叉树T存在,e是T中的某个结点*/
/*操作结果:返回e的左孩子。若e无左孩子,返回空*/
TElemType LeftChild(SqBiTree T, TElemType e)
{
//判断是否为空树
if (T[0]==Nil)
return Nil;
for(int i=0;i<=MAX_TREE_SIZE-1;i++)
{
if (T[i]==e)
{
return T[i*2+1];
}
}
return Nil;//没找到e
}
/*操作结果,返回右孩子;若无右孩子,返回空*/
TElemType RightChild(SqBiTree T, TElemType e)
{
if (T[0]==Nil)
return Nil;
for (int i=0; i<=MAX_TREE_SIZE-1; i++)
{
if (T[i]==e)
{
return T[(i+1)*2];
}
}
return Nil;//没找到e,返回空
}
/*初始条件:二叉树T存在,e是T中的某个结点*/
/*操作结果:返回e的做兄弟。若e是左孩子或无左兄弟,返回空*/
TElemType LeftBrother(SqBiTree T, TElemType e)
{
if (T[0]==Nil)
return Nil;
for (int i=1; i<=MAX_TREE_SIZE-1;i++)
{
if (T[i]==e && i%2==0)
{
return T[i-1];
}
}
return Nil;//没找到e,或者e就是左孩子
}
//返回e的右兄弟
TElemType RightBrother(SqBiTree T, TElemType e)
{
if (T[0]==Nil)
return Nil;
for(int i=1; iif (T[i]==e && i%2==1 /*&&T[i+1]!=Nil*/)
{
return T[i+1];
}
}
return Nil;//没找到e
}
/*PreOrderTraverse()调用*/
void PreTraverse(SqBiTree T, int e)
{
visit_SqBiTree(T[e]);
if (T[2*e+1]!=Nil) //左子树不为空
{
PreTraverse(T,2*e+1);
}
if (T[2*e+2]!=Nil) //右子树不为空
{
PreTraverse(T,2*e+2);
}
}
/*初始条件:二叉树存在*/
/*操作结果:先序遍历T(先序是指根节点先)*/
Status PreOrderTraverse(SqBiTree T)
{
if (isBiTreeEmpty(T))
return ERROR;
PreTraverse(T,0);
printf("\n");
return OK;
}
//中序遍历InOrderTraverse()调用
void InTraverse(SqBiTree T,TElemType e)
{
if (T[2*e+1]!=Nil) //左子树不为空,先左子树
{
InTraverse(T,2*e+1);
}
visit_SqBiTree(T[e]); //第二才是对应根节点
if (T[2*e+2]!=Nil) //第三是右子树
{
InTraverse(T,2*e+2);
}
}
/*初始条件:二叉树T存在*/
/*操作结果:中序遍历*/
Status InOrderTraverse(SqBiTree T)
{
if (!isBiTreeEmpty(T))
{
InTraverse(T,0);
}
printf("\n");
return OK;
}
//后续遍历PostOrderTraverse()的调用函数
void PostTraverse(SqBiTree T, TElemType e)
{
if (T[2*e+1]!=Nil)
{
PostTraverse(T,2*e+1);
}
if (T[2*e+2]!=Nil)
{
PostTraverse(T,2*e+2);
}
visit_SqBiTree(T[e]);
}
//后序遍历
Status PostOrderTraverse(SqBiTree T)
{
if (!isBiTreeEmpty(T))
{
PostTraverse(T,0);
}
printf("\n");
return OK;
}
/*层序遍历二叉树*/
void LevelOrderTraverse(SqBiTree T)
{
//注意:要先找到最后一个非空节点的序号,然后再依次遍历
int i=MAX_TREE_SIZE-1;
while(T[i]==Nil)
i--;
for (int j=0;j<=i;j++)
{
if (T[j]!=Nil) //只遍历非空结点
visit_SqBiTree(T[j]);
}
printf("\n");
}
/*逐层、按照本层序号输出二叉树*/
void Print(SqBiTree T)
{
Position p;
TElemType e;
for(int j=1;j<=BiTreeDepth(T);j++)
{
printf("第%d层:",j);
for(int i=1;i<=powl(2,j-1);i++)
{
p.level=j;
p.order=i;
e=Value(T,p);
if (e!=Nil)
{
printf("第%d个:%d",i,e);
}
}
printf("\n");
}
}
int main()
{
Status i;
Position p;
TElemType e;
SqBiTree T;
InitBiTree(T);
CreateBiTree(T);
printf("建立二叉树之后,树是否为空?%d(1:是;0:否)\n",isBiTreeEmpty(T));
printf("树的深度为%d\n",BiTreeDepth(T));
i=Root(T,&e);
if (i)
{
printf("二叉树的根节点为%d\n",i);
}
else
printf("二叉树为空");
printf("先序遍历二叉树:\n");
PreOrderTraverse(T);
printf("中序遍历二叉树:\n");
InOrderTraverse(T);
printf("后序遍历二叉树:\n");
PostOrderTraverse(T);
printf("层序遍历二叉树:\n");
LevelOrderTraverse(T);
printf("修改结点的层号3本层序号2.(第三层的第二个结点)");
p.level=3;
p.order=2;
e=Value(T,p);
printf(" %d",e);
e=50;
Assign(T,p,e);
printf("修改后,前序遍历二叉树:\n");
PreOrderTraverse(T);
printf("结点%d的双亲为%d,左右孩子分别为%d和%d",e,Parent(T,e),LeftChild(T,e),RightChild(T,e));
getchar();
}
首先要构造链式表的结构体,如下:
//和单链表类似。区别在于多了一个指针
typedef struct BiTNode
{
TelemType data;//存放数据
struct BiTNode *lchild,*rchild;//构造两个指针分别指向左子树和右子树
}BitNode,*BiTree;
其次,二叉链表在使用的时候,注意力在于根节点与左孩子和右孩子之间的关系。
/************************************************************************/
/* 树的链式存储结构 :二叉链表 */
/************************************************************************/
#include
#include
#include
#include
#include
#include
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXSIZE 100
typedef int Status;
typedef char TElemType;
TElemType Nil2 =' '; //字符型以空格为空,(整型Nil=0)
/******用于构造二叉树*******/
int index=1;
typedef char String[24];//定义一个字符型数组String,其中0号单元存放串的长度
String str; //main()函数中用到
Status StrAssignBiTree(String T, char *chars) //生成一个字符串T,其值等于chars
{
int i;
if (strlen(chars) > MAXSIZE)
return ERROR;
else
{
T[0]=strlen(chars);
for (i=1; i<=T[0]; i++)
{
T[i]=*(chars+i-1);
}
return OK;
}
}
/**************************************/
Status visitBiTree(TElemType e)
{
printf("%c",e);
return OK;
}
typedef struct BiTNode /*定义结点结构*/
{
TElemType data; //结点数据,TElemTypeChar型
struct BiTNode *lchild, *rchild; //定义左右孩子指针
}BiTNode, *BiTree;
//构造空的二叉树T
Status InitBiTree(BiTree *T)
{
*T =NULL;
return OK;
}
/*初始条件:二叉树T存在。操作结果:销毁二叉树*/
void DestroyBiTree(BiTree *T)
{
if (*T)
{
if ((*T)->lchild) //有左孩子
{
DestroyBiTree(&(*T)->lchild); //销毁左孩子树
}
if ((*T)->rchild)
{
DestroyBiTree(&(*T)->rchild);
}
free(*T); //释放根节点
*T=NULL; //空指针赋0
}
}
#define ClearBiTree DestroyBiTree
/* 按前序输入二叉树中结点的值(这里设置的是一个字符)*/
/* #表示空树,构造二叉链表表示二叉树T */
void CreateBiTree(BiTree *T)
{
TElemType ch;
ch=str[index++];
if (ch=='#') //空树
{
*T=NULL;
}
else
{
*T=(BiTree)malloc(sizeof(BiTNode));
if (!*T)
exit(OVERFLOW); //表示未分配到合适大小的空间
(*T)->data=ch;
CreateBiTree(&(*T)->lchild); //构造左子树
CreateBiTree(&(*T)->rchild); //构造右子树
}
}
/* 初始条件:二叉树T存在 */
/* 操作结果:若T为空二叉树,返回TRUE;否则返回FALSE */
Status isBiTreeEmpty(BiTree T)
{
if(T)
return FALSE;
else
return TRUE;
}
/* 初始条件:二叉树T存在。 操作结果:返回T的深度 */
int BiTreeDepth(BiTree T)
{
int i,j;
if(!T)
return ERROR;
if (T->lchild)
i=BiTreeDepth(T->lchild);
else
i=0;
if (T->rchild)
j=BiTreeDepth(T->rchild); //因为不一定是完全二叉树,所以有可能是各种奇怪的二叉树。因此既要判断左子树,也要判断右子树
else
j=0;
return i>j?i+1:j+1;
}
/* 初始条件:二叉树T存在。 操作结果:返回T的根 */
TElemType Root(BiTree T)
{
if (!T)
return Nil2;
else
return T->data;
}
/* 初始条件:二叉树T存在,p指向T中的某个结点 */
/* 操作结果:返回p所指向结点的值 */
TElemType Value(BiTree p)
{
return p->data; //
}
//给p所指向的结点赋值为value
void Assign(BiTree p, TElemType value)
{
p->data =value;
}
/*初始条件:二叉树T存在。操作结果:前序遍历T*/
void PreOrder(BiTree T)
{
if (!T)
return;
printf("%c ",T->data); //显示结点数据
PreOrder(T->lchild);
PreOrder(T->rchild);
}
/* 初始条件:二叉树T存在。操作结果:中序遍历T*/
void InOrder(BiTree T)
{
if (!T)
return;
InOrder(T->lchild);
printf("%c ",T->data);
InOrder(T->rchild);
}
/* 后序遍历*/
void PostOrder(BiTree T)
{
if(!T)
return;
PostOrder(T->lchild);
PostOrder(T->rchild);
printf("%c ",T->data);
}
int main()
{
int i;
BiTree T;
TElemType e1;
InitBiTree(&T);
StrAssignBiTree(str,"ABDH#K###E##CFI###G#J##");
CreateBiTree(&T);
printf("构造空二叉树后,树是否为空?%d(1:空;0:否),树的深度为%d\n",isBiTreeEmpty(T),BiTreeDepth(T));
e1=Root(T);
printf("树的根为%c\n",e1);
printf("\n前序遍历结果:");
PreOrder(T);
printf("\n中序遍历结果:");
InOrder(T);
printf("\n后序遍历结果:");
PostOrder(T);
ClearBiTree(&T);
printf("\n清除二叉树后,树是否为空?%d(1:空;0:否),树的深度为%d\n",isBiTreeEmpty(T),BiTreeDepth(T));
i=Root(T);
if (!i)
printf("树空,无根\n");
getchar();
return 0;
}