数据结构-树知识点总结(一)期末复习专用

第五章 树
5.1 树的基本概念-非线性结构(分支关系和层次特性)

根结点,叶(子)结点。

树的定义是递归的:一棵树是由子树构成,子树由更小的子树构成。一棵树至少有一个结点。

结点的次数是该结点子树的个数。叶子结点次数为0。树的次数是各结点次数的最大值。m次完全树:非叶子结点的次数都为m。

父结点,子结点,兄弟(同胞)结点。

根结点所在层次为0,其他结点层次为父结点所在层次加1

树中层次最大的结点的层次称为树的深度(Depth)或高度 (Height)。

路径:自上而下得到达,也叫树枝。路径长度,也叫树枝长度。根结点到树中其余节点一定存在路径。祖先、后代都不包括结点自身。

有序树:从左到右标好序号,尽量左不空。

5.2 树的(链式)存贮结构

一般形式(链式存贮结构)

data pointer

(一)标准形式存贮结构

data c h i l d 0 child_0 child0 c h i l d 1 child_1 child1…… c h i l d m − 1 child_{m-1} childm1

(二)逆形式存贮结构

data parent

(三)扩充标准形式

data c h i l d 0 child_0 child0 c h i l d 1 child_1 child1…… c h i l d m − 1 child_{m-1} childm1 parent
5.4 树的遍历

(1)前序遍历——先访问根结点,再前序遍历各子树

(2)后序遍历——先后序遍历各子树,再访问根结点

(3)层次遍历——先访问第0层上的根结点,然后访问第一层上各结点,依次访问结点

前序后序遍历的递归程序

//m次树 结点的常用结构 
struct node {
    char data; //结点的标识 
    struct node * child[MAXN]; }; 

Typedef struct node NODE; 

void r_preorder(NODE *t, int m) //递归前序遍历,t:根,m:次数 
{ int i; 
 if (t!=NULL) i
{ printf(%c”,t->data); 
  for (i=0;i<m;i++)   
     r_preorder(t->child[i],m); 
} 
}

非递归前序、层次遍历程序

//非递归程序实现树的前序遍历 
void s_preorder((NODE *t, int m) 
{ NODE * s[MAXN];//栈:用于保存尚未遍历树的根节点的地址 
 int top,i; 
 if (t==NULL) return; //t为空则停止 
 S[0]=t;  //入栈 top=1;  //top:下一次入栈的位置 
 while (top>0)//栈不空 
 { t=s[--top];  //栈顶结点出栈, 
  printf(%c”,t->data); //访问当前“根”节点 
  for (i=m-1;i>=0;i--) //从右向左依次入栈 
      if(t ->child[i] != NULL) 
          s[top ++] = t ->child[i]; 
 } 
}

//实现按层次遍历
使用一个顺序存储的队列存放还没有处理的子树的根结点的地址。 
void levorder(NODE *t, int m) {  
    NODE *q[100],*p ; 
    int head,tail,i; 
    if (t==NULL) return; 
    q[0]=t;  
    head=0; tail=1;  //队列 
    while (head<tail) 
    { p=q[head++];  //出队 
     printf(%c”,p->data); 
     for (i=0;i<m;i++)   //从左到右连续入队 
         if(p ->child[i] != NULL) 
             s[tail++] = p ->child[i]; 
    } }
           

1.初值入栈

2.当栈不为空

3.退栈一个、打印

4.连续入栈。

注:非递归层次把栈换为队即可。

5.5 树的顺序存贮结构

一、双亲存储法

(1)编号:从上到下,从左到右,从0(根结点)开始,依次递增编号

(2)存储:一维数组tree[n],下标即为该结点编号,每个元素为一个结构体,包含两个成员,data和parent,data为值,parent为父结点下标。根结点的tree [0].parent 为-1

编程:已知双亲表示存储法—>标准形式存贮结构

二、括号表示法,不考
5.6 二叉树

左子结点,右子结点,左子树,右子树,左儿子,右儿子。二叉树可以为空

任意次数转化为二叉树:儿子结点做左子树,同胞结点做右子树。

森林到二叉树的转换,图会画,递归程序会写。

5.7 二叉树的遍历

前序(根,左,右)、中序(左,根,右)、后序遍历(左,右,根)

三个递归程序:if(t!=null),printf……

//中序遍历+
void r_midorder(NODE *t)
{
    if(t!=NULL)
    {
        r_midorder(t->lchild);
        printf("%c",t->data);
        r_midorder(t->rchild);
    }
}
//前序遍历
void r_preorder(NODE *t)
{
    if(t!=NULL)
    {
        printf("%c",t->data);
        r_preorder(t->lchild);
        r_preorder(t->rchild);
    }
}
//后序遍历
void r_posorder(NODE *t)
{
    if(t!=NULL)
    {
        r_posorder(t->lchild);
        r_posorder(t->rchild);
        printf("%c",t->data);
    }
}

四个应用:

1.复制二叉树。

2.判断两棵二叉树是否等价。

3.求二叉树的高度。

4.求结点的数量。

5.求叶子结点的数量。

NODE *copy(NODE *t)//复制二叉树
{	
    if(t==NULL) return NULL;
    root=(NODE *)malloc(sizeof(NODE *));
    root->data=t->data;
    root->lchild=copy(t->lchild);
    root->rchild=copy(t->rchild);
    return root;
}

//求树的高度: 
int BiTreeDepth(BiTree t) 
{ 
    if (!T) return (-1) 
        else 
        { if ((!T->lchild)&&(!T->rchild)) return (0) 
          else hL= BiTreeDepth(T->lchild); 
              rL= BiTreeDepth(T->人child)return (max {hL,rL}+1} 
}

//结点的数量
int count (struct NODE  * root) 
{ 
  	if (root==NULL)  return (0); 
 	lcount=count(root->lchild); 
 	rcount=count(root->rchild); 
 	return (lcount+rcount+1); 
}

//求叶子结点的个数 
void CountLeaf(BiTree T, int& count) 
{ 	if (T)  //递归程序,先考虑好结束条件 
	{ 	if ((!T->lchild)&&(!T->rchild)) //T是叶子结点 
    		count++; 
 		CountLeaf(T->lchild, count); 
     	CountLeaf(T->rchild, count); 
} 
}
Int equaltree(t1,t2) 
    NODE *t1,*t2 
{ if t1空并且t2空 return (1); 
 	if (t1不空且t2不空) 
     if (t1和t2的数据字段相等) 
         ifequaltree(t1->lchild,t2->lchild)return(equaltree(t1->rchild,t2->rchild); 
	return (0);
}

5.8 二叉树的顺序存储

满二叉树:高度为h且有 2 h + 1 − 1 2^{h+1}-1 2h+11个结点的二叉树

完全二叉树:也叫拟满树,除最后一层外,是满二叉树。最后一层从最右结点向左看无空位置。

二叉树的性质:

(1)如果从0开始计数二叉树的层次,则在第i层最多有 2 i 2^i 2i个 结点。(i≥0);
(2)高度为h的二叉树,最多有 2 h + 1 − 1 2^{h+1}-1 2h+11个结点( h≥0 );
(3)任意一棵二叉树,如果其叶结点有n0个,次数为2的非叶 结点有n2个,则有n0=n2+1;
(4)具有n(n>0 )个结点的完全二叉树的深度为 ⌊ log ⁡ 2 n ⌋ \lfloor \log_2 n \rfloor log2n
注:二叉树的高度:沿用树的定义,只有一个根节点的时候,高度为0 ,空二叉树高度为-1.

完全二叉树具有如下性质:具有n(n>0)个结点的完全二叉树 的深度为 ⌊ log ⁡ 2 n ⌋ \lfloor \log_2 n \rfloor log2n

完全二叉树的层次存储法:

一维数组,自上到下自左到右,从0(根结点)编号,用编号做下标值。对于非完全树,可将其补成完全二叉树,添加null结点。

父结点, ⌊ ( i − 1 ) / 2 ⌋ \lfloor (i-1)/2 \rfloor i1/2

按前序的存储结构

(1)附加左标志位和右指针。(ltag,data,rchild)

ltag=0:结点k后面的结点是k的左子结点,有左结点。

ltag=1:结点k无左子结点。

rchild:记录其右子结点数组下标。(用-1表示空结点)

(2)附加两个标志位—左标志位和右标志位。(ltag,data,rtag)

ltag=0/rtag=0:有左结点,有右结点。

ltag=1/rtag=1:没有左结点,没有右结点。

5.9 穿线树和穿线排序

对于一棵具有n个结点的二叉树,如果按标准形式存贮,那么总共有2n个指针,其中只有(n-1)个用来指向子结点,另外(n+1)个指针是空的。

按中序遍历得到序列。

5个域: l c h i l d 、 l t a g 、 d a t a 、 r t a g 、 r c h i l d lchild、ltag、data、rtag、rchild lchildltagdatartagrchild

两个特殊指针:根指针root,head指针指向中序遍历的第一个结点。

两个特殊结点:中序遍历第一个结点:ltag=0,最后一个结点:rtag=0。

图会画。

5.10 计算二叉树的数目

如果有n个结点,那么将有多少棵不同的子树?

1 n + 1 C 2 n n \frac{1}{n+1}C{^n_{2n}} n+11C2nn。卡塔兰数

给定前序,中序,画出二叉树。

你可能感兴趣的:(数据结构,树结构,二叉树)