数据结构——树

1、树的基本定义

1、树的定义:n个结点的有限集合(n>=0)。
2、树的结点:包含1个数据元素及若干指向其子树的分支。
3、结点的度:结点所拥有的子树数量。
4、树的度:树中所有结点的度的最大值。
5、结点的层次:从根节点开始为第一层
6、树的深度:最大的层次数。

/2、二叉树(Binary Tree)

1、二叉树:n个结点的有限集合(n>=0)。特殊在于:n>1时,1个根节点和两棵互不相交的二叉树。
2、满二叉树:①所有的分支结点都有左子树和右子树;②所有的叶子结点都在同一层。
3、完全二叉树:对有n个结点的二叉树按照层序编号,若编号i(1<=i<=n)与同样深度的满二叉树的位置完全相同,则该二叉树为完全二叉树。
4、二叉树的一些性质:

/2.1 二叉树的顺序结构

注意:逻辑结构和物理结构的差异。
逻辑结构:分为线性和非线性。(树是非线性结构)
物理结构(存储结构):分为顺序、链式、索引、哈希等,表征数据是如何存储的。(因此树结构也可以有顺序或链式存储结构)

二叉树的顺序存储结构如下:

//二叉树的顺序结构中:一个数组和一个表示位置的结构体。数组存放数据,下标从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;i<MAX_TREE_SIZE;i++)
        T[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(i<MAX_TREE_SIZE)
    {
        T[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; i<MAX_TREE_SIZE;i++)
    {
        if (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();

}

2.2 二叉树的链式结构:二叉链表

首先要构造链式表的结构体,如下

//和单链表类似。区别在于多了一个指针
typedef struct BiTNode
{
    TelemType data;//存放数据
    struct BiTNode *lchild,*rchild;//构造两个指针分别指向左子树和右子树
}BitNode,*BiTree;       

其次,二叉链表在使用的时候,注意力在于根节点与左孩子和右孩子之间的关系。

/************************************************************************/
/* 树的链式存储结构  :二叉链表                                               */
/************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <math.h>
#include <time.h>
#include <string.h>


#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;


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值