树:
n个结点的有限集,n=0时为空树,在任意一棵非空树中:1.有且仅有一个特定的称为根的结点;2.n>1时,其余节点可分为m个互不相交的有限集,每个集合本身又是一棵树-称为根的子树
#根唯一--子集互相不相交
结点的度:结点拥有的子树数目
树的度:取各结点的最大值
度为0称为叶节点--度不为0称为分支结点或非终端结点
树中最大层次称为树的深度或高度//第一层、第二层...
#双亲、兄弟、堂兄弟
有序树:从左到右有次序
森林:m棵互不相交的树
树的存储结构:
双亲表示法:以双亲为索引的关键字的一种存储方式--除了自身数据还存有指向双亲的指针(下标)
孩子表示法:(多重链表):
1.根据树的度申请足够的空间存放子树指针的结点--资源浪费
2.在结点元素后面加上一个度的数据,申请定量的空间--但初始化+维护难度巨大-时间浪费
3.数组+链表--数组中存放第一个孩子的地址,然后一个单链表所有的孩子连起来
//双亲孩子表示法
#define max_tree_size 100
typedef char elemtype
typedef struct CTNode
{
int child; //孩子结点下标
struct CTNode *next //指向下一个孩子的指针
} *childptr ;
//表头结构
typedef struct
{
elemtype data; //存放在树中结点的数据
int parent; //存放双亲的下标
childptr firstchile; //指向第一个孩子的指针
} ctbox;
//树结构
typedef struct
{
ctbox nodes(max_tree_size); //结点数组
int r,n;
}
二叉树:
是n个结点的有限集合,该集合为空集,或是有一个根节点+两棵互不相交分别称为根节点的左子树和右子树的二叉树组成。
#最多有两个子树,可以有一个或是没有
#左子树和右子树有次序,即使只有一棵树,也要区分左右
五种基本形态:1.空二叉树、2.只有一个根节点、3.只有左子树、4.只有右子树、5.全都有
特殊二叉树:1.斜树-往一边斜、2.满二叉树-所有分支节点都有左右子树+所有叶子在同一层、3.完全二叉树--序号从左到右,从上往下和满二叉树的序号位置完全一样(完全二叉树可以少一部份最右下层的叶子)、
二叉树的性质:
1.第i层至多有2^(i-1)个结点
2.深度为k的二叉树至多有2^k-1个结点
3.对于任何一棵二叉树T,如果其终端结点数为n0,杜威2的结点数位n2,则n0=n2+1
4.具有n结点的完全二叉树的深度位[log2(n)]+1 //取整
.....
二叉树的存储结构:
顺序存储结构:由于严格要求定义,可以在数组上直接表现逻辑结构(不存在的点用一个符号代替)
链式存储结构:(一般也用这种方式存储)//数据左右各一个指针--二叉链表
typedef struct binode
{
elemtype data
struct bitnode *lchild *rchild
} bitnode *bitree
二叉树的遍历:
遍历是指从根结点出发按照某种次序依次访问所有结点,使得每个结点被访问一次
遍历方式:
1.前序遍历:空,否则根节点-前序遍历左子树-前序遍历右子树
2.中序遍历:空,否则中序遍历左子树-根结点-中序遍历右子树(降到同一直线从左往右)
3.后序遍历:空,否则从左到右先叶子后结点-最后根结点
4.层序遍历:按层
建立二叉树:
//前序遍历-建立二叉树
#include
#include
typedef char elemtype;
typedef struct bitnode
{
char data;
struct bitnode *lchild ,*rchild;
}bitnode,*bitree;
//创建二叉树,约定前序遍历
createbitree(bitree *T)
{
char c;
scanf("%c",&c);
if(' '==c)
{
*T=NULL;
}
else
{
*T=(bitnode *)malloc(sizeof(bitnode));
(*T)->data=c;
createbitree(&(*T)->lchild);
createbitree(&(*T)->rchild);
}
}
//访问二叉树结点的具体操作
visit(char c,int level)
{
printf("%c位于第%d层\n",c,level);
}
//遍历二叉树
preordertraverse(bitree T,int level)
{
if( T )
{
visit(T->data,level); //1
preordertraverse(T->lchild,level+1); //2
preordertraverse(T->rchild,level+1); //3
//前序遍历 123,后序遍历231,中序遍历213
}
}
int main()
{
int level=1;
bitree T=NULL;
createbitree(&T);
preordertraverse(T,level);
return 0;
}
线索二叉树:
选择中序遍历,每隔一个会有造成浪费的结点,利用这些空间放前驱和后继
将定义好的结构进行扩容:lchild .ltag .data .rtag .rchild
Tag为0时,指向左孩子,1时指向前驱
程序中存在修改过程--
//中序遍历-建立线索二叉树
#include
#include
typedef char elemtype;
//link(0)--指向左右孩子的指针//thread(1)指向前驱后继的线索
typedef enum {link , thread} pointernag;
typedef struct bitnode
{
pointernag ltag;
pointernag rtag;
char data;
struct bitnode *lchild ,*rchild;
}bitnode,*bitree;
//全局变量- 始终指向刚刚访问过的结点
bitree pre;
//创建二叉树,按照前序遍历
createbitree(bitree *T)
{
char c;
scanf("%c",&c);
if(' '==c)
{
*T=NULL;
}
else
{
*T=(bitnode *)malloc(sizeof(bitnode));
(*T)->data=c;
//多出来的那部分
(*T)->ltag=link;
(*T)->rtag=link;
createbitree(&(*T)->lchild);
createbitree(&(*T)->rchild);
}
}
//访问二叉树结点的具体操作
visit(char c,int level)
{
printf("%c位于第%d层\n",c,level);
}
//遍历二叉树--中序
preordertraverse(bitree T,int level)
{
if( T )
{
preordertraverse(T->lchild,level+1);
if( !T->lchild) //如果该节点没有左孩子,设置ltag为thread并把lchild指向前驱
{
T->ltag = thread;
T->lchild=pre;
}
if( !pre->rchild )
{
pre->rtag =thread;
pre->rchild =T;
}
pre =T;
preordertraverse(T->rchild,level+1);
}
}
inorderthreading(bitree *p ,bitree T)
{
*p = (bitree)malloc(sizeof(bitnode));
(*p)->ltag=link;
(*p)->rtag=thread;
(*p)->rchild=*p;
if(!T)
{
(*p)->lchild=*p;
}
else
{
(*p)->lchild=T;
pre=*p;
preordertraverse(T,1);
pre->rchild=*p;
pre->rtag =thread;
(*p)->rchild=pre;
}
}
visit2(char c)
{
printf("%c\n",c);
}
//中序遍历二叉树,非递归
void inordertraverse(bitree T)
{
bitree p;
p=T->lchild ;
while (p!=T)
{
while(p->ltag ==link)
{
p=p->lchild;
}
visit2(p->data);
while(p->rtag ==thread && p->rchild !=T)
{
p=p->rchild ;
visit2(p->data );
}
p=p->rchild ;
}
}
int main()
{
int level=1;
bitree T=NULL, p=NULL;
createbitree(&T);
inorderthreading( &p,T );
printf("输出结果为:\n");
inordertraverse(p);
return 0;
}