二叉树的二叉链表的表示和各种函数的实现


//二叉树的二叉链表表示和各种实现
//用顺序栈来实现遍历的非递归操作
//用队列来帮助实现一些函数

//二叉树的二叉链表表示和各种实现
//用顺序栈来实现遍历的非递归操作
//用队列来帮助实现一些函数




#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>


typedef    char        TElemType;
typedef    int         Status;


#define    OK          1
#define    ERROR       0


#define    INIT_SIZE   100
#define    INCREMENT   10






/***********************************/
//树的节点类型
typedef  struct  BiTNode
{
    TElemType  data;
    struct BiTNode   *lchild,*rchild;
}BiTNode,*BiTree;


/***********************************/


typedef   BiTree     SElemType;
typedef   BiTree     QElemType;




/**********************************/
/***队列的各个函数的 定义*********/










//链表队列节点类型
typedef  struct QNode
{
    QElemType     data;
    struct QNode  * next;
}QNode;


//链表队列类型
typedef struct  LinkQueue
{
    QNode *front;//指向链表的对头节点,用来删除
    QNode *rear;//指向链表的队尾节点,用来插入
}LinkQueue;






//初始化一个队列
Status   InitQueue (LinkQueue *Q)
{
    //让队头指针合队尾指针均指向头结点
    Q->front = Q->rear = (QNode *)malloc(sizeof(QNode ));//生成一个头结点类型
    if(!Q->front)
    {
        printf("队列初始化失败:内存分配失败\n");
        return ERROR;
    }
    return  OK;
}




//销毁一个队列
Status  DestroyQueue(LinkQueue * Q)
{


    while(Q->front)//如果Q->front 不为空
    {
        Q->rear=Q->front->next;
        free(Q->front);
        Q->front=Q->rear;
    }
    return OK;
}


//判断是否为空队列,如果是空队列,则返回OK,如果不是空队列,则返回ERROR
Status  QueueEmpty(LinkQueue *Q)
{
    if(Q->rear==Q->front)//如果对头指针和队尾指针相同则是空队列,头指针始终指向头节点
        return OK;
    return ERROR;
}




//向队列中插入元素
Status  EnQueue(LinkQueue *Q,QElemType e)
{
    QNode *s=(QNode *)malloc(sizeof(QNode));
    if(!s)
        return  ERROR;
    s->data=e;
    s->next=NULL;
    Q->rear->next=s;
    Q->rear=s;
    return OK;
}


//从队列中删除元素,并将元素值存放在e中
Status  DeQueue(LinkQueue *Q,QElemType  *e)
{
    if(Q->front==Q->rear)//队列为空
        return ERROR;
    QNode *s=Q->front->next;//令s指向队列的对头节点
    *e=s->data;
    Q->front->next=s->next;
    if(Q->rear==s)//如果只有一个元素
        Q->rear=Q->front;
    free(s);
    return OK;


}


/**********************************/
/******顺序栈的有关函数定义*******/






//顺序栈的结构类型
typedef  struct
{
    SElemType    *base;//地址空间的基址
    SElemType    *top;//顺序栈的栈顶指针
    int          stacksize;//分配到的地址大小
}SqStack;




//初始化一个栈
Status  InitStack(SqStack *S)
{
    S->base=(SElemType*)malloc(sizeof(SElemType)*(INIT_SIZE));
    if(!(S->base))
    {
        printf("栈空间内存分配失败\n");
        return ERROR;
    }
    S->top=S->base;
    S->stacksize=INIT_SIZE;
    return  OK;
}




//判断栈是否为空
Status  StackEmpty(SqStack *S)
{
    if(S->top==S->base)
        return OK;
    else
        return ERROR;
}




//若栈不空,则用e返回S的栈顶元素,并且返回1;否则返回0
Status GetTop(SqStack *S,SElemType *e)
{
    if((S->top)-(S->base)>0)
    {
        *e=*(S->top-1);
        return OK;
    }
    else
        return ERROR;
}




//插入元素e作为新的栈顶元素
Status  Push(SqStack  *S,SElemType e)
{
    if((S->top)-(S->base)>=S->stacksize)//栈满
    {
        S->base=(SElemType *)realloc(S->base,sizeof(SElemType)*(INIT_SIZE+INCREMENT));
        if(!S->base)
        {
            printf("栈满,且重新分配内存空间失败\n");
            return  ERROR;
        }
        S->top=S->base+S->stacksize;
        S->stacksize+=INCREMENT;
    }
    *(S->top)=e;
    S->top++;
    return OK;
}


//栈顶元素出栈,并且用e记录其值
Status  Pop(SqStack *S,SElemType *e)
{
    if(S->top==S->base)//如果是空栈
        return ERROR;
    else
    {
        *e = *(--S->top);
        return OK;
    }


}
/******************************************/
/******************************************/






//用Nil表示空字符
TElemType  Nil=' ';




//构造空二叉树
Status  InitBiTree(BiTree *T)
{
    *T=NULL;
    return OK;
}




//销毁整个二叉树
Status  DestroyBiTree(BiTree *T)
{
    if(!*T)
        return  ERROR;
    else
    {
        if((*T)->lchild)//如果存在左孩子
            DestroyBiTree(&(*T)->lchild);
        if((*T)->rchild)
            DestroyBiTree(&(*T)->rchild);
        free(*T);
        *T=NULL;//将*T赋值为NULL
    }
    return OK;
}




#define  ClearBiTree     DestroyBiTree;




// 按先序次序输入二叉树中结点的值,构造二叉链表表示的二叉树T
// 变量Nil表示空(子)树。
void  CreateBiTree(BiTree  *T)
{
    TElemType   c;
    scanf("%c",&c);
    if(c==Nil)
        *T=NULL;
    else
    {
        *T=(BiTree)malloc(sizeof(BiTNode));
        if(!*T)
            exit(0);
        (*T)->data=c;
        CreateBiTree(&(*T)->lchild);//递归构造左子树
        CreateBiTree(&(*T)->rchild);//递归构造右子树
    }
}


//判断树是否为空树
Status  BiTreeEmpty(BiTree T)
{
    if(!T)//如果指针是空的话就是空树
        return OK;
    else
        return ERROR;
}




//返回树的深度
int  BiTreeDepth(BiTree  T)
{
    if(BiTreeEmpty(T))//如果树为空树 ,则返回0
        return 0;
    else
    {


        return (BiTreeDepth(T->lchild)>=BiTreeDepth(T->rchild)?BiTreeDepth(T->lchild):BiTreeDepth(T->rchild))+1;
    }
}




//返回树的根值
TElemType  Root(BiTree T)
{
    if(BiTreeEmpty(T))//如果T为空
        return Nil;
    else
        return T->data;
}


//返回指针p指向的 值
TElemType  Value(BiTree p)
{
    return p->data;
}




//给指针p所指向的节点重新赋值
void     Assign(BiTree p,TElemType value)
{
    p->data=value;
}




//二叉树T存在,e是T中的某一个节点,若e是T中的非根节点,则返回它的双亲的值,否则返回“空”
TElemType  Parent(BiTree  T,TElemType  e)
{
    //思想是和层次遍历队列一样的。从每一层的节点开始搜索。依次进行判断
    //只不过是加了判断条件
    LinkQueue  *Q=(LinkQueue *)malloc(sizeof(LinkQueue));
    InitQueue(Q);
    if(T->data==e)
    {
        printf("节点是根节点,没有双亲节点\n");
        return Nil;
    }
    EnQueue(Q,T);
    BiTree p;
    //BiTree *p=(BiTree *)malloc(sizeof(BiTree));
    while(!QueueEmpty(Q))//如果队列不为空
    {
        DeQueue(Q,&p);
        if(p->lchild&&(p->lchild)->data==e)
        {
             return p->data;//返回双亲的值
             break;
        }
        if(p->rchild&&(p->rchild)->data==e)
        {
            return p->data;
            break;
        }
        else
        {
            if(p->lchild)
                EnQueue(Q,p->lchild);
            if(p->rchild)
                EnQueue(Q,p->rchild);
        }
    }
    return Nil;//树中没有这个节点
}


//返回二叉树T中指向元素值为e的节点的指针
BiTree  Point(BiTree T,TElemType e)
{
    LinkQueue Q;
    InitQueue(&Q);
    EnQueue(&Q,T);
    QElemType a;


    while(!QueueEmpty(&Q))//队列为非空
    {
        DeQueue(&Q,&a);
        if(a->data==e)
            return a;
        if(a->lchild)
            EnQueue(&Q,a->lchild);
        if(a->rchild)
            EnQueue(&Q,a->rchild);
    }
    return NULL;




}


//二叉树T存在,e是T中的某个节点。返回T的左孩子,若无左孩子,则返回空
TElemType  LeftChild(BiTree T,TElemType e)
{
    BiTree a;
    if(T)
    {
        a=Point(T,e);//获取e的指针
        if(a&&a->lchild)
            return (a->lchild)->data;
    }
    return Nil;
}


//二叉树T存在,e是T中的某个节点。返回T的右孩子,若无右孩子,则返回空
TElemType  RightChild(BiTree T,TElemType e)
{
    BiTree a;
    if(T)
    {
        a=Point(T,e);//获取e的指针
        if(a&&a->rchild)
            return a->rchild->data;
    }
    return Nil;
}




//二叉树T存在,e是T中的某个节点,返回e的左兄弟,若e是T的左孩子或者无左兄弟,则返回空
TElemType LeftSibling(BiTree T,TElemType  e)
{
    if(!T)
        return Nil;
    TElemType par=Parent(T,e);
    BiTree   p=Point(T,par);
    if(!p->lchild||p->lchild->data==e)//如果左孩子为空或者e是T的其父的左孩子
        return Nil;
    else
    {
        return  p->lchild->data;
    }
}




//二叉树T存在,e是T中的某个节点,返回e的右兄弟,若e是T的右孩子或者无右兄弟,则返回空
TElemType RightSibling(BiTree T,TElemType  e)
{
    if(!T)
        return Nil;
    TElemType par=Parent(T,e);
    BiTree   p=Point(T,par);
    if(!p->rchild||p->rchild->data==e)
        return Nil;
    else
    {
        return  p->rchild->data;
    }
}


//二叉树T存在,p指向T中的某个节点,LR为0或者1
//非空二叉树c与T不想交且右子树为空,根据LR为0或1,插入c为T中p所指向节点的左或者右字树
//p所指向节点的原有左子树或者右子树则成为c的右子树
Status  InsertChild(BiTree T,BiTree p,int LR, BiTree c)
{
    if(!T)
        return ERROR;
    if(p)//如果p不为空
    {
        if(LR==0)//插入c为T中p所指节点的左子树
        {
            if(p->lchild&&p->rchild)
                return ERROR;
            p->lchild=c;
            c->rchild=p->lchild;
        }
        else if(LR==1)//插入c为T中p所指节点的右子树
        {
             if(p->lchild&&p->rchild)
                return ERROR;
            c->rchild=p->rchild;
            p->rchild=c;
        }
        else
            return ERROR;
    }
}


//二叉树T存在,p指向T中的某个节点,LR为0或1
//根据LR 为0或者1,删除T中p所指节点的左或右子树
Status  DeleteChild(BiTree T,BiTree p,int LR)
{
    if(p)
    {
        if(LR==0)
            DestroyBiTree(p->lchild);
        else if(LR==1)
            DestroyBiTree(p->rchild);
        return OK;


    }
    return ERROR;


}
//访问函数
int PrintElement(TElemType e)
{
    printf("%c ",e);
    return 1;
}




// 先序递归遍历T,对每个结点调用函数PrintElement一次且仅一次
void PreOrderTraverse(BiTree T,int(*PrintElement)(TElemType))
{
    if(T) // T不空
    {
        PrintElement(T->data); // 先访问根结点
        PreOrderTraverse(T->lchild,PrintElement); // 再先序遍历左子树
        PreOrderTraverse(T->rchild,PrintElement); // 最后先序遍历右子树
    }


}


// 中序递归遍历T,对每个结点调用函数PrintElement一次且仅一次
void InOrderTraverse(BiTree T,int(*PrintElement)(TElemType))
{
    if(T) //T不为空
    {
        InOrderTraverse(T->lchild,PrintElement);
        PrintElement(T->data);
        InOrderTraverse(T->rchild,PrintElement);
    }


}




// 后序递归遍历T,对每个结点调用函数PrintElement一次且仅一次
void PostOrderTraverse(BiTree T,int(*PrintElement)(TElemType))
{


    if(T) //T不为空
    {
        PostOrderTraverse(T->lchild,PrintElement);
        PostOrderTraverse(T->rchild,PrintElement);
        PrintElement(T->data);
    }


}


/*利用堆栈来实现树的一些非递归遍历*/
/*将指向树节点的指针作为栈的类型节点的内容*/


/************************************前序非递归遍历的两种写法*************************************/
//前序遍历二叉树T的非递归算法(第一种方法),对每个数据元素调用PrintElement函数
Status PreOrderNonResusiveTraverse(BiTree  T,int(*PrintElement(TElemType)))
{
    SqStack *S=(SqStack*)malloc(sizeof(SqStack));
    InitStack(S);
    while(T||(!StackEmpty(S)))
    {
        if(T)
        {
            if(!PrintElement(T->data))
                return ERROR;
            Push(S,T);
            T=T->lchild;
        }
        else
        {
            Pop(S,&T);
            T=T->rchild;


        }
    }
    printf("\n");
    return OK;
}
// 错误的方法.
//前序遍历二叉树T的非递归算法(第二种方法),对每个数据元素调用PrintElement函数
Status PreOrderNonResusiveTraverse2(BiTree  T,int(*PrintElement(TElemType)))
{
    // 初始化一个栈
    SqStack *S=(SqStack*)malloc(sizeof(SqStack));
    InitStack(S);


    //首先访问根节点,并且压入栈中
    Push(S,T);
    //BiTree  value;//value实际的值是BiTree 指针
    while(!StackEmpty(S))
    {
        while(GetTop(S,&T)&&T)//一直将左孩子访问并放入到栈中
        {
            PrintElement(T->data);
            T=T->lchild;
            //PrintElement(T->data);
            Push(S,T);//一直将左孩子节点压入栈中
        }
        Pop(S,&T);
        //如果栈为非空,则出栈一个元素,并且判断是否有右孩子。
        //直接找到第一个右孩子的节点,并且出栈将指针指向它,重新循环~
        while(!StackEmpty(S))
        {
            Pop(S,&T);
            if(T->rchild)
            {
                T=T->rchild;
                Push(S,T);
                break;
            }


        }
    }
    return OK;


}




/************************************前序非递归遍历的两种写法*************************************/






/************************************中序非递归遍历的两种写法*************************************/
//中序遍历二叉树T的非递归算法(第一种方法),对每个数据元素调用PrintElement函数
Status InOrderNonResusiveTraverse(BiTree  T,int(*PrintElement(TElemType)))
{
    SqStack *S=(SqStack*)malloc(sizeof(SqStack));
    InitStack(S);
    Push(S,T);//先将根节点入栈
    BiTree *e=(BiTree* )malloc(sizeof(BiTree));
    while(!StackEmpty(S))//如果栈为非空
    {
        /*遍历左子树,向左一直走到尽头*/
        while(GetTop(S,e)&&(*e))
            Push(S,(*e)->lchild);
        Pop(S,e);//将最后的空指针退栈
        if(!StackEmpty(S))//如果栈为非空,则访问节点,并且向右走一步,继续遍历其子树
        {
            Pop(S,e);
            if(!(PrintElement((*e)->data)))
                return ERROR;
            Push(S,(*e)->rchild);
        }//if
    }//while
    printf("\n");
    return OK;
}




//中序遍历二叉树T的非递归算法(第二种方法),对每个数据元素调用PrintElement函数
Status InOrderNonResusiveTraverse2(BiTree  T,int(*PrintElement(TElemType)))
{
    SqStack *S=(SqStack *)malloc(sizeof(SqStack));
    InitStack(S);//初始化一个栈
    while(T||!StackEmpty(S))//当树不为空的情况或者栈不为空的情况下
    {
        if(T)//如果左孩子存在
        {
             Push(S,T);
             T=T->lchild;
        }
        else
        {


            Pop(S,&T);
            if(!PrintElement(T->data))
                return ERROR;
            T=T->rchild;
        }
    }//while
    printf("\n");
    return OK;


}
/************************************中序非递归遍历的两种方法*************************************/




/************************************后序非递归遍历的方法*****************************************/




//后序遍历二叉树T的非递归算法(第二种方法),对每个数据元素调用PrintElement函数






/************************************后序非递归遍历的方法*****************************************/




/*层序遍历二叉树T的算法,对每个数据元素调用PrintElement函数*/
//思想是
Status LevelOrderTraverse(BiTree  T,int(*PrintElement(TElemType)))
{
    LinkQueue  *Q=(LinkQueue *)malloc(sizeof(LinkQueue));
    InitQueue(Q);
    if(!T)
    {
        printf("空树\n");
        return ERROR;
    }
    EnQueue(Q,T);//先将树根节点放入到队列中
    BiTree *p=(BiTree *)malloc(sizeof(BiTree));


    while(!QueueEmpty(Q))//如果队列不为空
    {
        DeQueue(Q,p);
        if((*p)->lchild)
            EnQueue(Q,(*p)->lchild);
        if((*p)->rchild)
            EnQueue(Q,(*p)->rchild);
        if(!PrintElement((*p)->data))
            return ERROR;
    }
    return  OK;


}


int  main()
{
    printf("输入你想要构建的二叉树.(空格表示空子树)****\n");
    BiTree T=(BiTree )malloc(sizeof(BiTNode));
    InitBiTree(&T);




    printf("初始化树为%d (1为空,0为非空)\n",BiTreeEmpty(T));


    CreateBiTree(&T);
    printf("构造完后树是否为空%d (1为空,0为非空)\n",BiTreeEmpty(T));


    printf("树的深度为%d\n",BiTreeDepth(T));


    printf("前序递归遍历为:\n");
    PreOrderTraverse(T,PrintElement);
    printf("\n");


    printf("前序非递归遍历的第一种方法:\n");
    PreOrderNonResusiveTraverse(T,PrintElement);
    printf("\n");


    printf("前序非递归遍历的第二种方法:\n");
    PreOrderNonResusiveTraverse2(T,PrintElement);
    printf("\n");




    printf("递归中序遍历为:\n");
    InOrderTraverse(T,PrintElement);
    printf("\n");


    printf("非递归中序遍历(第一种方法)为:\n");
    InOrderNonResusiveTraverse2(T,PrintElement);
    printf("\n");


    printf("非递归中序遍历(第一种方法)为:\n");
    InOrderNonResusiveTraverse2(T,PrintElement);
    printf("\n");


    printf("后序遍历为:\n");
    PostOrderTraverse(T,PrintElement);
    printf("\n");


    printf("层次遍历为:\n");
    LevelOrderTraverse(T,PrintElement);
    printf("\n");
    printf("---下面是树的函数的一些测试实例---\n");


    fflush(stdin);
    TElemType  e2,e3;
    fflush(stdin);
    printf("输入 你想查看的节点的值:\n");
    scanf("%c",&e2);
    e3=Parent(T,e2);
    printf("输入值的双亲是%c:\n",e3);
    printf("输入值的左孩子是%c:\n",LeftChild(T,e2));
    printf("输入值的右孩子是%c:\n",RightChild(T,e2));
    printf("输入值的左兄弟是%c:\n",LeftSibling(T,e2));
    printf("输入值的右兄弟是%c:\n",RightSibling(T,e2));


    return 0;
}




下图是验证的二叉树图片:

 

 


这里讲一下代码过程主要遇到的几个问题:

1:在调用函数中修改传递的指针问题,看下面的代码。

//构造空二叉树
Status  InitBiTree(BiTree *T)
{
    *T=NULL;
    return OK;
}
首先BiTree 就是指向BiTnode 类型的一个指针,在InitBiTree函数中想修改T的值,就必须传递T 的指针进去,刚开始编码的时候在这里忘记了。小卡了一下!

2:输入的问题:

根据我们定义的输入函数:

// 按先序次序输入二叉树中结点的值,构造二叉链表表示的二叉树T

void  CreateBiTree(BiTree  *T)
{
    TElemType   c;
    scanf("%c",&c);
    if(c==Nil)
        *T=NULL;
    else
    {
        *T=(BiTree)malloc(sizeof(BiTNode));
        if(!*T)
            exit(0);
        (*T)->data=c;
        CreateBiTree(&(*T)->lchild);//递归构造左子树
        CreateBiTree(&(*T)->rchild);//递归构造右子树
    }
}

因为这个构造函数是按照先序遍历构造的,所以说如果你想构造下面图中的树的时候:

你必须以下面的形式输入(#代表空格):ab#ce#fw###d##gh###,然后按回车(#再输入的过程中表示空格)

3:在写LeftChild的函数时遇到了段错误。是因为使用了p->leftchild->data 这个语句的时候没有提前判断p->lchild  这个是否为空。导致程序不能正常执行。对于这种问题,在访问节点的时候首先应该判断节点是否为空,然后才能执行某种操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值