二叉树链式实现

文章目录
一、定义
二、结构
三、常用操作

一、定义
        二叉树是n (n≥0)个结点的有限集合:
        (1)、或者为空二叉树,即n = 0。
        (2)、或者由一个根结点和两个互不相交的被称为根的左子树和右子树组成。左子树和右子树又分别是一棵二叉树。

二、结构
结构示意图:


代码表示:

 #define ElemType char //结点内数据的类型
//树结点结构
typedef struct BinTreeNode
{
    ElemType data;  //数据域
    struct BinTreeNode *leftChild; //左孩子
    struct BinTreeNode *rightChild; //右孩子
}BinTreeNode;

//二叉树根结点管理
typedef struct BinTree
{
    BinTreeNode *root;//根结点
    ElemType     refvalue; //stop flag 停止的标记(用来设置停止的记号)
}BinTree;


三、常用操作
二叉树初始化

//二叉树初始化
void InitBinTree(BinTree *bt, ElemType ref)
{
    bt->root = NULL;//根设置为空
    bt->refvalue = ref; //设置停止标记
}

二叉树创建

 方式一

//方式一:使用二级指针
//供外部调用
void CreateBinTree_1(BinTree *bt)
{
    CreateBinTree_1(bt,&(bt->root));
}
//内部实现
void CreateBinTree_1(BinTree *bt, BinTreeNode **t)
{
    ElemType Item; //接收数据
    scanf("%c",&Item);
    if(Item == bt->refvalue) //判断输入是否为一个结束标记
        (*t) = NULL;//是 说明这棵二叉树是空树
    else
    {//否
        //创建树(子树)根结点
        (*t) = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        assert((*t) != NULL);
        (*t)->data = Item;//为结点赋值
        CreateBinTree_1(bt,&((*t)->leftChild)); //创建左子树
        CreateBinTree_1(bt,&((*t)->rightChild)); //创建右子树
    }
}


 方式二

//方式二:使用C++指针引用方式
//对外调用
void CreateBinTree_2(BinTree *bt)
{
    CreateBinTree_2(bt,bt->root);
}
//内部实现
void CreateBinTree_2(BinTree *bt, BinTreeNode *&t)
{
    ElemType Item;//接收数据
    scanf("%c",&Item);
    if(Item == bt->refvalue)//判断输入是否为一个结束标记
        t = NULL;//是 说明这棵二叉树是空树
    else
    {

        //创建链表头结点,即创建树(子树)根结点
        t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        assert(t != NULL);
        t->data = Item;//为结点赋值
        CreateBinTree_2(bt,t->leftChild); //创建左子树
        CreateBinTree_2(bt,t->rightChild); //创建右子树
    }
}


  方式三

//方式三:通过返回值返回二叉树
void CreateBinTree_3(BinTree *bt)
{
    bt->root = CreateBinTree_3_(bt);
}
BinTreeNode* CreateBinTree_3_(BinTree *bt)
{
    ElemType Item; //接收数据
    scanf("%c",&Item);
    if(Item == bt->refvalue) //判断输入是否为一个结束标记
        return NULL;//是 说明这棵二叉树是空树
    else
    {//否
        //创建树(子树)根结点
        BinTreeNode *t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        assert(t != NULL);
        t->data = Item;//为结点赋值
        t->leftChild = CreateBinTree_3_(bt);//创建左子树
        t->rightChild = CreateBinTree_3_(bt);//创建右子树
        return t;//返回所创建的树
    }
}



方式四

//方式4:传入要创建的二叉树的串进行创建
void CreateBinTree_4(BinTree *bt, char *str)
{
    CreateBinTree_4(bt,bt->root,str);
}

//char *&str是引用方式,因为指针也是传值方式,要想后续使用改变后的指针,要用引用或者指针的指针
void CreateBinTree_4(BinTree *bt, BinTreeNode *&t, char *&str)
{
    if(*str == bt->refvalue) //判断输入是否为一个结束标记
        t = NULL;  //是 说明这棵二叉树是空树
    else
    {
        //创建树(子树)根结点
        t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        assert(t != NULL);
        t->data = *str;//为结点赋值
        CreateBinTree_4(bt,t->leftChild,++str);//创建左子树
        CreateBinTree_4(bt,t->rightChild,++str);//创建右子树
    }
}


 方式五

//根据二叉树的前序和中序序列创建树
void CreateBinTree_5(BinTree *bt, char *VLR, char *LVR, int n)
{
    //n结点个数
    CreateBinTree_5(bt->root,VLR,LVR,n);
}

void CreateBinTree_5(BinTreeNode *&t, char *VLR, char *LVR, int n)
{
    if(n == 0)
        t = NULL;
    else
    {
        int k = 0;
        //利用先序序列,查找根在中序序列的位置
        while(VLR[0] != LVR[k])
            k++;

        //创建根
        t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        assert(t != NULL);
        t->data = LVR[k];

        //创建t的左子树
        CreateBinTree_5(t->leftChild,VLR+1,LVR,k);
        //创建右子树
        CreateBinTree_5(t->rightChild,VLR+k+1,LVR+k+1,n-k-1);
    }
}


方式六

//根据中序和后序序列创建二叉树
void CreateBinTree_6(BinTree *bt, char *LVR, char *LRV, int n)
{
    CreateBinTree_6(bt->root,LVR,LRV,n);
}
void CreateBinTree_6(BinTreeNode *&t, char *LVR, char *LRV, int n)
{
    if(n == 0)
        t = NULL;
    else
    {
        //利用后序序列,查找根在中序序列的位置
        int k = 0;
        while(LRV[n-1] != LVR[k]) //后序需要从后往前找根
            k++;

        //创建根结点
        t = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        assert(t != NULL);
        t->data = LVR[k];
        //创建右子树
        CreateBinTree_6(t->rightChild,LVR+k+1,LRV+k,n-k-1);
        //创建左子树
        CreateBinTree_6(t->leftChild,LVR,LRV,k);
    }
}


二叉树遍历

这里讲的是将输入的二叉树字符串用二叉树进行存储。为了表示左右子树为空,还需要特殊的标记值来标记,这样才能生成一个正确的二叉树。

  1、递归方式

先序遍历

二叉树先序遍历的实现思想是:

  1. 访问根节点;
  2. 访问当前节点的左子树;
  3. 若当前节点无左子树,则访问当前节点的右子树;

                                                                            图 1 二叉树

以图  1 为例,采用先序遍历的思想遍历该二叉树的过程为:

  1. 访问该二叉树的根节点,找到 1;
  2. 访问节点 1 的左子树,找到节点 2;
  3. 访问节点 2 的左子树,找到节点 4;
  4. 由于访问节点 4 左子树失败,且也没有右子树,因此以节点 4 为根节点的子树遍历完成。但节点 2 还没有遍历其右子树,因此现在开始遍历,即访问节点 5;
  5. 由于节点 5 无左右子树,因此节点 5 遍历完成,并且由此以节点 2 为根节点的子树也遍历完成。现在回到节点 1 ,并开始遍历该节点的右子树,即访问节点 3;
  6. 访问节点 3 左子树,找到节点 6;
  7. 由于节点 6 无左右子树,因此节点 6 遍历完成,回到节点 3 并遍历其右子树,找到节点 7;
  8. 节点 7 无左右子树,因此以节点 3 为根节点的子树遍历完成,同时回归节点 1。由于节点 1 的左右子树全部遍历完成,因此整个二叉树遍历完成;


因此,图 1 中二叉树采用先序遍历得到的序列为:

1 2 4 5 3 6 7

//先序遍历
void PreOrder(BinTree *bt)
{
    PreOrder(bt->root);
}
void PreOrder(BinTreeNode *t)
{
    if(t != NULL)//树不为空
    {
        printf("%c ",t->data);//访问(子树)根结点
        PreOrder(t->leftChild);//访问左子树
        PreOrder(t->rightChild);//访问右子树
    }
}


  中序遍历

二叉树中序遍历的实现思想是:

  1. 访问当前节点的左子树;
  2. 访问根节点;
  3. 访问当前节点的右子树;

                                                                           图 1 二叉树

以图  1 为例,采用中序遍历的思想遍历该二叉树的过程为:

  1. 访问该二叉树的根节点,找到 1;
  2. 遍历节点 1 的左子树,找到节点 2;
  3. 遍历节点 2 的左子树,找到节点 4;
  4. 由于节点 4 无左孩子,因此找到节点 4,并遍历节点 4 的右子树;
  5. 由于节点 4 无右子树,因此节点 2 的左子树遍历完成,访问节点 2;
  6. 遍历节点 2 的右子树,找到节点 5;
  7. 由于节点 5 无左子树,因此访问节点 5 ,又因为节点 5 没有右子树,因此节点 1 的左子树遍历完成,访问节点 1 ,并遍历节点 1 的右子树,找到节点 3;
  8. 遍历节点 3 的左子树,找到节点 6;
  9. 由于节点 6 无左子树,因此访问节点 6,又因为该节点无右子树,因此节点 3 的左子树遍历完成,开始访问节点 3 ,并遍历节点 3 的右子树,找到节点 7;
  10. 由于节点 7 无左子树,因此访问节点 7,又因为该节点无右子树,因此节点 1 的右子树遍历完成,即整棵树遍历完成;


因此,图 1 中二叉树采用中序遍历得到的序列为:

4 2 5 1 6 3 7

//中序遍历
void InOrder(BinTree *bt)
{
    InOrder(bt->root);
}
void InOrder(BinTreeNode *t)
{
    if(t != NULL)
    {
        InOrder(t->leftChild);//访问左子树
        printf("%c ",t->data);//访问(子树)根
        InOrder(t->rightChild);//访问右子树
    }
}


  后序遍历

二叉树后序遍历的实现思想是:从根节点出发,依次遍历各节点的左右子树,直到当前节点左右子树遍历完成后,才访问该节点元素。

                                                                            图 1 二叉树
 

如图 1 中,对此二叉树进行后序遍历的操作过程为:

  • 从根节点 1 开始,遍历该节点的左子树(以节点 2 为根节点);
  • 遍历节点 2 的左子树(以节点 4 为根节点);
  • 由于节点 4 既没有左子树,也没有右子树,此时访问该节点中的元素 4,并回退到节点 2 ,遍历节点 2 的右子树(以 5 为根节点);
  • 由于节点 5 无左右子树,因此可以访问节点 5 ,并且此时节点 2 的左右子树也遍历完成,因此也可以访问节点 2;
  • 此时回退到节点 1 ,开始遍历节点 1 的右子树(以节点 3 为根节点);
  • 遍历节点 3 的左子树(以节点 6 为根节点);
  • 由于节点 6 无左右子树,因此访问节点 6,并回退到节点 3,开始遍历节点 3 的右子树(以节点 7 为根节点);
  • 由于节点 7 无左右子树,因此访问节点 7,并且节点 3 的左右子树也遍历完成,可以访问节点 3;节点 1 的左右子树也遍历完成,可以访问节点 1;
  • 到此,整棵树的遍历结束。

由此,对图 1 中二叉树进行后序遍历的结果为:

4 5 2 6 7 3 1 

//后序遍历
void PostOrder(BinTree *bt)
{
    PostOrder(bt->root);
}
void PostOrder(BinTreeNode *t)
{
    if(t != NULL)
    {
        PostOrder(t->leftChild);//访问左子树
        PostOrder(t->rightChild);//访问右子树
        printf("%c ",t->data);//访问(子树)根
    }
}


2、非递归方式

二叉树层次遍历:按照二叉树中的层次从左到右依次遍历每层中的结点。具体的实现思路是:通过使用队列的数据结构,从树的根结点开始,依次将其左孩子和右孩子入队。而后每次队列中一个结点出队,都将其左孩子和右孩子入队,直到树中所有结点都出队,出队结点的先后顺序就是层次遍历的最终结果。

                                                                          图1 二叉树

层次遍历的实现过程

例如,层次遍历图 1 中的二叉树:

  • 首先,根结点 1 入队;
  • 根结点 1 出队,出队的同时,将左孩子 2 和右孩子 3 分别入队;
  • 队头结点 2 出队,出队的同时,将结点 2 的左孩子 4 和右孩子 5 依次入队;
  • 队头结点 3 出队,出队的同时,将结点 3 的左孩子 6 和右孩子 7 依次入队;
  • 不断地循环,直至队列内为空。

  非递归层次遍历:层次遍历需要借用队列结构,此处给出队列的结构

//队列结构

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

struct BinTreeNode;

#define EType BinTreeNode*

typedef struct QueueNode
{
    EType data;
    struct QueueNode *next;
}QueueNode;

typedef struct LinkQueue
{
    QueueNode *front;
    QueueNode *tail;
}LinkQueue;

void InitQueue(LinkQueue *Q);
bool QueueIsEmpty(LinkQueue *Q);
void EnQueue(LinkQueue *Q, EType x);
void ShowQueue(LinkQueue *Q);
void DeQueue(LinkQueue *Q);
void GetHead(LinkQueue *Q, EType *v);
int Length(LinkQueue *Q);
void ClearQueue(LinkQueue *Q);
void DestroyQueue(LinkQueue *Q);

void InitQueue(LinkQueue *Q)
{
    QueueNode *s = (QueueNode *)malloc(sizeof(QueueNode));
    assert(s != NULL);
    Q->front = Q->tail = s;
    Q->tail->next = NULL;
}

bool QueueIsEmpty(LinkQueue *Q)
{
    return Q->front == Q->tail;
}

void EnQueue(LinkQueue *Q, EType x)
{
    QueueNode *s = (QueueNode *)malloc(sizeof(QueueNode));
    assert(s != NULL);
    s->data = x;
    s->next = NULL;

    Q->tail->next = s;
    Q->tail = s;
}

void ShowQueue(LinkQueue *Q)
{
    QueueNode *p = Q->front->next;
    printf("Front:>");
    while(p != NULL)
    {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("<:Tail.\n");
}

void DeQueue(LinkQueue *Q)
{
    if(Q->front == Q->tail)
        return;

    QueueNode *p = Q->front->next;

    Q->front->next = p->next;
    free(p);
    if(p == Q->tail)
        Q->tail = Q->front;
}

void GetHead(LinkQueue *Q, EType *v)
{
    if(Q->front == Q->tail)
        return;
    QueueNode *p = Q->front->next;
    *v = p->data;
}

int Length(LinkQueue *Q)
{
    int len = 0;
    QueueNode *p = Q->front->next;
    while(p != NULL)
    {
        len++;
        p = p->next;
    }
    return len;
}

void ClearQueue(LinkQueue *Q)
{
    if(Q->front == Q->tail)
        return;
    QueueNode *p = Q->front->next;
    while(p != NULL)
    {
        Q->front->next = p->next;
        free(p);
        p = Q->front->next;
    }
    Q->tail = Q->front;
}

void DestroyQueue(LinkQueue *Q)
{
    ClearQueue(Q);
    free(Q->front);
    Q->front = Q->tail = NULL;
}


  下面介绍具体实现

//非递归方式层次遍历
void LevelOrder(BinTree *bt)
{
    LevelOrder(bt->root);
}
void LevelOrder(BinTreeNode *t)
{
    if(t != NULL)
    {
        BinTreeNode *v;
        LinkQueue Q; //创建队列
        InitQueue(&Q); //对队列初始化
        EnQueue(&Q,t);//将二叉树根结点(地址)入队

        while(!QueueIsEmpty(&Q)) //判断队列是否为空
        {//不空
            GetHead(&Q,&v);//取(子树)根结点(地址)
            DeQueue(&Q);//将(子树)根结点(地址)出队
            printf("%c ",v->data);//打印出(子树)根结点的数据
            if(v->leftChild != NULL) //判断该结点的左树是否为空
                EnQueue(&Q,v->leftChild); //否 将左子树(地址)入队
            if(v->rightChild != NULL) //判断该结点右子树是否为空
                EnQueue(&Q,v->rightChild);//否 将右子树(地址)入队
        }
    }
}


非递归方式先序遍历、中序遍历和后序遍历  

而对于先序遍历、中序遍历和后序遍历的非递归实现需要用到栈结构,下面给出它们的栈结构。

 先序遍历和中序遍历非递归形式使用的栈结构

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

struct BinTreeNode;

#define ET BinTreeNode*

#define STACK_INIT_SIZE  8
#define STACK_INC_SIZE   3

typedef struct SeqStack
{
    ET *base;
    int       capacity;
    int       top;
}SeqStack;

bool Inc(SeqStack *s);

void InitStack(SeqStack *s);
bool IsFull(SeqStack *s);
bool IsEmpty(SeqStack *s);

void Push(SeqStack *s, ET x);
void Pop(SeqStack *s);
bool GetTop(SeqStack *s, ET *v);
void Show(SeqStack *s);
int Length(SeqStack *s);
void Clear(SeqStack *s);
void Destroy(SeqStack *s);

/

void InitStack(SeqStack *s)
{
    s->base = (ET *)malloc(sizeof(ET)*STACK_INIT_SIZE);
    assert(s->base != NULL);
    s->capacity = STACK_INIT_SIZE;
    s->top = 0;
}

bool Inc(SeqStack *s)
{
    ET *newbase = (ET *)realloc(s->base,sizeof(ET)*(s->capacity+STACK_INC_SIZE));
    if(newbase == NULL)
    {
        printf("内存不足,无法申请空间.\n");
        return false;
    }
    s->base = newbase;
    s->capacity += STACK_INC_SIZE;
    return true;
}

bool IsFull(SeqStack *s)
{
    return s->top >= s->capacity;
}
bool IsEmpty(SeqStack *s)
{
    return s->top == 0;
}

void Push(SeqStack *s, ET x)
{
    if(IsFull(s) && !Inc(s))
    {
        printf("栈空间已满,%d 不能入栈.\n",x);
        return;
    }

    s->base[s->top++] = x;
    //s->top++;
}

void Pop(SeqStack *s)
{
    if(IsEmpty(s))
    {
        printf("栈空间已空,不能出栈.\n");
        return;
    }

    s->top--;
}

bool GetTop(SeqStack *s, ET *v)
{
    if(IsEmpty(s))
    {    
        printf("栈空间已空,不能取栈顶元素.\n");
        return false;
    }

    *v = s->base[s->top-1];
    return true;
}

void Show(SeqStack *s)
{
    for(int i=s->top-1; i>=0; --i)
    {
        printf("%d\n",s->base[i]);
    }
    printf("\n");
}

int Length(SeqStack *s)
{
    return s->top;
}

void Clear(SeqStack *s)
{
    s->top = 0;
}
void Destroy(SeqStack *s)
{
    free(s->base);
    s->base = NULL;
    s->capacity = s->top = 0;
}


  后序遍历非递归实现使用的栈结构

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

struct BinTreeNode;

typedef enum{L,R}Tag; //左右标记

typedef struct StkNode
{
    BinTreeNode *ptr;
    Tag          tag;  
}StkNode;  //栈结构

#define ET StkNode

#define STACK_INIT_SIZE  8
#define STACK_INC_SIZE   3

typedef struct SeqStack
{
    ET *base;
    int       capacity;
    int       top;
}SeqStack;

bool Inc(SeqStack *s);

void InitStack(SeqStack *s);
bool IsFull(SeqStack *s);
bool IsEmpty(SeqStack *s);

void Push(SeqStack *s, ET x);
void Pop(SeqStack *s);
bool GetTop(SeqStack *s, ET *v);
void Show(SeqStack *s);
int Length(SeqStack *s);
void Clear(SeqStack *s);
void Destroy(SeqStack *s);

/

void InitStack(SeqStack *s)
{
    s->base = (ET *)malloc(sizeof(ET)*STACK_INIT_SIZE);
    assert(s->base != NULL);
    s->capacity = STACK_INIT_SIZE;
    s->top = 0;
}

bool Inc(SeqStack *s)
{
    ET *newbase = (ET *)realloc(s->base,sizeof(ET)*(s->capacity+STACK_INC_SIZE));
    if(newbase == NULL)
    {
        printf("内存不足,无法申请空间.\n");
        return false;
    }
    s->base = newbase;
    s->capacity += STACK_INC_SIZE;
    return true;
}

bool IsFull(SeqStack *s)
{
    return s->top >= s->capacity;
}
bool IsEmpty(SeqStack *s)
{
    return s->top == 0;
}

void Push(SeqStack *s, ET x)
{
    if(IsFull(s) && !Inc(s))
    {
        printf("栈空间已满,%d 不能入栈.\n",x);
        return;
    }

    s->base[s->top++] = x;
    //s->top++;
}

void Pop(SeqStack *s)
{
    if(IsEmpty(s))
    {
        printf("栈空间已空,不能出栈.\n");
        return;
    }

    s->top--;
}

bool GetTop(SeqStack *s, ET *v)
{
    if(IsEmpty(s))
    {    
        printf("栈空间已空,不能取栈顶元素.\n");
        return false;
    }

    *v = s->base[s->top-1];
    return true;
}

void Show(SeqStack *s)
{
    for(int i=s->top-1; i>=0; --i)
    {
        printf("%d\n",s->base[i]);
    }
    printf("\n");
}

int Length(SeqStack *s)
{
    return s->top;
}

void Clear(SeqStack *s)
{
    s->top = 0;
}
void Destroy(SeqStack *s)
{
    free(s->base);
    s->base = NULL;
    s->capacity = s->top = 0;
}


 下面介绍具体实现:

  先序遍历的非递归实现

//先序遍历的非递归实现
void PreOrder_1(BinTree *bt)
{
    PreOrder_1(bt->root);
}
void PreOrder_1(BinTreeNode *t)
{
    if(t != NULL) //判断二叉树是否为空
    {
        SeqStack st;   //申请一个栈
        InitStack(&st); //初始化栈
        BinTreeNode *p;
        Push(&st,t); //将二叉树的根结点入栈
        while(!IsEmpty(&st)) //判断栈顶是否为空
        {//否
            GetTop(&st,&p);//获取栈顶结点
            Pop(&st);//出栈
            printf("%c ",p->data);//打印数据
            /*这里需要注意的是栈结构是先进后出的,所以后访问的结点先入栈*/
            if(p->rightChild != NULL) //判断右子树是否为空
                Push(&st,p->rightChild); //否 入栈
            if(p->leftChild != NULL) //判断左子树是否为空
                Push(&st,p->leftChild); //否 入栈
        }
    }
}


  中序遍历的非递归实现

//中序遍历:非递归实现
void InOrder_1(BinTree *bt)
{
    InOrder_1(bt->root);
}
void InOrder_1(BinTreeNode *t)
{
    if(t != NULL) //判断二叉树是否为空
    {//不空
        SeqStack st; //设置一个栈结构
        InitStack(&st); //初始化栈
        BinTreeNode *p;
        Push(&st,t); //将根结点入栈
        while(!IsEmpty(&st)) //判断栈是否为空
        {//不空
            //判断左子树是否为空
            while(t!=NULL && t->leftChild!=NULL)
            {//不空
                Push(&st,t->leftChild);//左子树入栈
                t = t->leftChild;//位置下移
            }
            //此时已经走到了左子树的尽头
            //获取栈顶元素
            GetTop(&st,&p);
            Pop(&st); //出栈
            printf("%c ",p->data); //打印元素
            //判断右子树是否为空
            if(p->rightChild != NULL)
            {//不空
                t = p->rightChild;//访问右子树
                if(t != NULL) //将右子树入栈
                    Push(&st,t);
            }
        }
    }
}


 后序遍历的递归实现

//后序遍历:非递归形式
void PostOrder(BinTree *bt)
{
    PostOrder(bt->root);
}
void PostOrder(BinTreeNode *t)
{
    if(t != NULL)
    {
        SeqStack st;
        InitStack(&st);
        BinTreeNode *p;
        StkNode sn;
        do
        {
            while(t != NULL)
            {
                sn.ptr = t;//指向二叉树树的根结点
                sn.tag = L; //刚开始访问左子树,标记为左
                Push(&st,sn);//入栈
                t = t->leftChild;//指向左子树的根结点
            }
            bool flag = true; //continue visit
            while(flag && !IsEmpty(&st))
            {
                GetTop(&st,&sn); //获取栈顶元素
                Pop(&st); //出栈
                p = sn.ptr; 
                switch(sn.tag) //看结点的标记信息
                {
                /*
                    如果标记是左标记,说明接下来还需要访问右子树,不能访问根结点,
                    如果标记是右标记,那么说明左右子树都已经访问完成可以访问根
                */
                case L: //左标记:接下来还需要访问右子树
                    sn.tag = R; //将左标记改为右
                    Push(&st,sn); //重新入栈
                    flag = false;
                    t = p->rightChild;//接下来要访问右子树
                    break;
                case R: //右标记 可以访问根结点,打印信息
                    printf("%c ",p->data);
                    break;
                }
            }
        }while(!IsEmpty(&st));//栈为空时,退出
    }
}


统计结点个数

//求以bt为根结点的二叉树结点个数
int Size(BinTree *bt)
{
    return Size(bt->root);
}
int Size(BinTreeNode *t)
{
    if(t == NULL)  //判断二叉树是否为空
        return 0;//是 记录个数为0
    else//否 该二叉树的结点个数=左子树结点个数+右子树结点个数+根结点个数(1)
        return Size(t->leftChild)+Size(t->rightChild)+1;
}


求二叉树高度

//求取二叉树的高度
int Height(BinTree *bt)
{
    return Height(bt->root);
}
int Height(BinTreeNode *t)
{
    if(t == NULL)  //判断二叉树是否为空
        return 0;//是 记录高度为0
    else
    {//否
        //求取左子树高度
        int left_height = Height(t->leftChild);
        //求取右子树高度
        int right_height = Height(t->rightChild);
        //返回:该二叉树高度=左子树与右子树的最大高度+1
        return (left_height>right_height ? left_height:right_height)+1;
    }
}


查找结点

//查找key值所在的结点
BinTreeNode* Search(BinTree *bt, ElemType key)
{
    return Search(bt->root,key);
}
BinTreeNode* Search(BinTreeNode *t, ElemType key)
{
    if(t == NULL) //判断二叉树是否为空
        return NULL; //是  说明不存在,返回空
    if(t->data == key) //否 判断结点值是否等于key值
        return t; //是  返回结点地址

    //没找到
    BinTreeNode *p = Search(t->leftChild,key); //查找左子树
    if(p != NULL)//判断是否找到
        return p;//找到  返回结点地址
    // 没找到
    return Search(t->rightChild,key); // 查找右子树,返回查找结果
}


查找某结点的父结点

//在bt二叉树中查找p结点的父结点
BinTreeNode* Parent(BinTree *bt, BinTreeNode *p)
{
    return Parent(bt->root,p);
}
BinTreeNode* Parent(BinTreeNode *t, BinTreeNode *p)
{
    if(t==NULL || p==NULL) //判断二叉树和结点是否为空
        return NULL;//是 返回空
    //否
    if(t->leftChild==p || t->rightChild==p)//判断t的左右孩子是否为p
        return t;// 是  返回其父结点
    //否
    BinTreeNode *q = Parent(t->leftChild,p);//查找t的左子树
    if(q != NULL)//判断左子树中是否找到满足条件的结点
        return q;// 是  返回
    //否
    return Parent(t->rightChild,p);//查找右子树
}


获取左子树

//获取二叉树的左子树
BinTreeNode* LeftChild(BinTreeNode *p)
{
    if(p != NULL)
        return p->leftChild;
    return NULL;
}


获取右子树

//获取二叉树的右子树  
BinTreeNode* RightChild(BinTreeNode *p)
{
    if(p != NULL)
        return p->rightChild;
    return NULL;
}


判断二叉树是否为空

//判断二叉树是否为空
bool BinTreeEmpty(BinTree *bt)
{
    return  bt->root==NULL;//判断根结点是否为空
}


拷贝二叉树

//拷贝二叉树:bt2拷贝到bt1
void Copy(BinTree *bt1, BinTree *bt2)
{
    Copy(bt1->root,bt2->root);
}
void Copy(BinTreeNode *&t1, BinTreeNode *t2)
{
    if(t2 == NULL) //判断t2是否为空
        t1 = NULL;//是 则无需拷贝,直接将t1置空
    else
    {//否

        //为t2(子树)根结点拷贝到t1(子树)根结点
        t1 = (BinTreeNode*)malloc(sizeof(BinTreeNode));
        assert(t1 != NULL);
        t1->data = t2->data;
        Copy(t1->leftChild,t2->leftChild);//拷贝t2左子树到t1左子树
        Copy(t1->rightChild,t2->rightChild);//拷贝t2右子树到t1右子树
    }
}


清空二叉树

//清空操作
void BinTreeClear(BinTree *bt)
{
    BinTreeClear(bt->root);
}
void BinTreeClear(BinTreeNode *&t)
{
    if(t != NULL) //判断二叉树是否为空
    {//否        
        BinTreeClear(t->leftChild);//清空左子树
        BinTreeClear(t->rightChild);//清空右子树
        free(t);//清空(子树)根
        t = NULL;
    }
}

main.c测试接口

#include"BinTree.h"

//ABC##DE##F##G#H##

void main()
{
    char *VLR = "ABCDEFGH";
    char *LVR = "CBEDFAGH";
    char *LRV = "CEFDBHGA";

    int n = strlen(VLR);

    BinTree mytree;
    InitBinTree(&mytree,'#');

    CreateBinTree_5(&mytree,VLR,LVR,n);

    BinTree youtree;
    InitBinTree(&youtree,'#');
    CreateBinTree_6(&youtree,LVR,LRV,n);

}

/*
void main()
{
    char *str = "ABC##DE##F##G#H##";
    BinTree mytree;
    InitBinTree(&mytree,'#');

    CreateBinTree_4(&mytree,str);

    PreOrder_1(&mytree);
    printf("\n");
    InOrder_1(&mytree);
    printf("\n");
}

/*
void main()
{
    char *str = "ABC##DE##F##G#H##";
    //char *str = "ABC##D##G#H##";
    BinTree mytree;
    InitBinTree(&mytree,'#');

    CreateBinTree_4(&mytree,str);

    PreOrder(&mytree);
    printf("\n");
    InOrder(&mytree);
    printf("\n");
    PostOrder(&mytree);
    printf("\n");
    LevelOrder(&mytree);
    printf("\n");

    printf("Size = %d\n",Size(&mytree));
    printf("Height = %d\n",Height(&mytree));
    BinTreeNode *p = Search(&mytree,'E');
    BinTreeNode *parent = Parent(&mytree,p);

    BinTree youtree;
    InitBinTree(&youtree,'#');
    Copy(&youtree,&mytree);

    BinTreeClear(&youtree);
}
*/

参考:

二叉树详解(C语言版)_二叉树c语言_红心火柴的博客-CSDN博客

数据结构(15.1)二叉树的遍历及其七种实现方式_实现二叉树的各种遍历算法数据结构_发量充足的小姚的博客-CSDN博客

数据结构(15.2)二叉树_发量充足的小姚的博客-CSDN博客

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值