考研C语言第十四章

14.3树与二叉树原理解析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
树并没有严格的要求,可以有多个子节点
在这里插入图片描述
二叉树特点:
1、分叉只有两个
2、左边的节点永远比上面的小,右节点永远比上面的节点大
当每一层的节点数量都是满的,称为满二叉树
在这里插入图片描述
这种就不是完全二叉树
只能右边空出来,哪种结构是完全二叉树
在这里插入图片描述
把中间所有的空位都留出来(不常考)
在这里插入图片描述
链式是重点
在这里插入图片描述

14.4二叉树层次建树实战

eg:输入abcdefghij
这个是没有数字大小关系的,因此在判断的时候,先让a为根节点,然后判断a的左孩子是不是NULL,是就让b这个数字入队,然后判断右孩子是否为NULL,将C放进去,剩下的都是这么循环遍历的
在这里插入图片描述
在这里插入图片描述
中心思想就是设置一个栈(通过链表实现)设置一个二叉树,先用先进先出把数据都读入进去,然后设置左孩子和右孩子节点
代码:
方法代码:

#ifndef INC_1_SQLIST_FUNCTION_H
#define INC_1_SQLIST_FUNCTION_H

#include <stdio.h>
#include <stdlib.h>
typedef char BiElemType;
typedef struct BiTNode{
    BiElemType c;//c 就是书籍上的 data
    struct BiTNode *lchild;
    struct BiTNode *rchild;
}BiTNode,*BiTree;

//tag 结构体是辅助队列使用的
typedef struct tag{
    BiTree p;//树的某一个结点的地址值
    struct tag *pnext;
}tag_t,*ptag_t;

#endif //INC_1_SQLIST_FUNCTION_H

主函数代码:

#include "function.h"

int main(){
    BiTree pnew;//用来指向新申请的树节点
    //树里面每个节点都用,不是还有头结点的那种
    BiTree tree=NULL;//tree是指向树根的,代表树
    char c;
    ptag_t phead=NULL,ptail=NULL,listpnew=NULL,pcur;
    //abcdefghij
    while(scanf("%c",&c))
    {
        if(c=='\n')
        {
            break;//读取到换行就结束
        }
        //calloc申请的空间大小是两个参数的乘积,calloc的好处是申请了空间之后,并且进行初始化,就很好
        pnew=(BiTree)calloc(1,sizeof(BiTNode));
        pnew->c=c;
        //给队列节点申请空间
        listpnew= (ptag_t)calloc(1,sizeof(tag_t));
        listpnew->p=pnew;
        //如果是树的第一个节点
        if(NULL==tree)
        {
            tree=pnew;//树的根
            phead=listpnew;//队列头
            ptail=listpnew;//队列尾
            pcur=listpnew;
            continue;
        }else{
            ptail->pnext=listpnew;//新结点放入链表,通过尾插法
            ptail=listpnew;//ptail 指向队列尾部
            //接下来把b节点放到树中
            if(NULL==pcur->p->lchild)//如何把新结点放入树
            {
                pcur->p->lchild=pnew;//把新结点放到要插入结点的左孩子
            }else if(NULL==pcur->p->rchild)
            {
                pcur->p->rchild=pnew;//把新结点放到要插入结点的右孩子
                pcur=pcur->pnext;//左右都放了结点后,pcur 指向队列的下一个,当前左右孩子都有了,就下一个节点
            }
        }//pcur 始终指向要插入的结点的位置

    }
//    }
    return 0;
}

14.5二叉树前序中序后序遍历实战

在这里插入图片描述
前序遍历使用preOrder实现
中序遍历使用InOrder实现
后序遍历使用PostOrder实现
在这里插入图片描述

前序遍历:这里讲的很好
就是把自己的孩子跟到自己的后面
一开始:
abc
先看左边b的孩子
abdec
再看右边c的孩子
abdecfg
再看d,e的孩子
abdhiejcfg
就写完了

中序遍历:主打一个左右孩子必须靠着父元素,先看完整个左子树再看右子树
一开始:
bac
看b的孩子们
dbeac
然后把h,i,j加上
hdibjeac
然后把c的孩子们加上
hdibjeafcg

后序遍历:(先打印左子树,在打印右子树,然后打印中间节点)
bca
然后看b的孩子
debca
然后看d和e的孩子
hidjebca
然后看右子树c的孩子
hidjebfgca

代码:

#include "function.h"

//前序遍历,深度优先遍历
void PreOrder(BiTree p)
{
    if(p!=NULL){
        printf("%c",p->c);
        PreOrder(p->lchild);//这就相当于递归打印左右子树
        PreOrder(p->rchild);
    }

}

//中序遍历
void InOrder(BiTree p)
{
    if(p!=NULL)
    {
        InOrder(p->lchild);
        printf("%c",p->c);
        PreOrder(p->rchild);

    }
}

//后序遍历
void PostOrder(BiTree p)
{
    if(p!=NULL)
    {
        InOrder(p->lchild);
        PreOrder(p->rchild);
        printf("%c",p->c);

    }
}

int main(){
    BiTree pnew;//用来指向新申请的树节点
    //树里面每个节点都用,不是还有头结点的那种
    BiTree tree=NULL;//tree是指向树根的,代表树
    char c;
    ptag_t phead=NULL,ptail=NULL,listpnew=NULL,pcur;
    //abcdefghij
    while(scanf("%c",&c))
    {
        if(c=='\n')
        {
            break;//读取到换行就结束
        }
        //calloc申请的空间大小是两个参数的乘积,calloc的好处是申请了空间之后,并且进行初始化,就很好
        pnew=(BiTree)calloc(1,sizeof(BiTNode));
        pnew->c=c;
        //给队列节点申请空间
        listpnew= (ptag_t)calloc(1,sizeof(tag_t));
        listpnew->p=pnew;
        //如果是树的第一个节点
        if(NULL==tree)
        {
            tree=pnew;//树的根
            phead=listpnew;//队列头
            ptail=listpnew;//队列尾
            pcur=listpnew;
            continue;
        }else{
            ptail->pnext=listpnew;//新结点放入链表,通过尾插法
            ptail=listpnew;//ptail 指向队列尾部
            //接下来把b节点放到树中
            if(NULL==pcur->p->lchild)//如何把新结点放入树
            {
                pcur->p->lchild=pnew;//把新结点放到要插入结点的左孩子
            }else if(NULL==pcur->p->rchild)
            {
                pcur->p->rchild=pnew;//把新结点放到要插入结点的右孩子
                pcur=pcur->pnext;//左右都放了结点后,pcur 指向队列的下一个,当前左右孩子都有了,就下一个节点
            }
        }//pcur 始终指向要插入的结点的位置

    }
    printf("-------PreOrder--------\n");
    PreOrder(tree);
    printf("\n");
    printf("-------InOrder--------\n");
    InOrder(tree);
    printf("\n");
    printf("-------PostOrder--------\n");
    PostOrder(tree);
    return 0;
}

在这里插入图片描述
使用递归就很好懂

14.6二叉树的层次遍历实战

代码:

#include "function.h"

//前序遍历,深度优先遍历
void PreOrder(BiTree p)
{
    if(p!=NULL){
        printf("%c",p->c);
        PreOrder(p->lchild);//这就相当于递归打印左右子树
        PreOrder(p->rchild);
    }

}

//中序遍历
void InOrder(BiTree p)
{
    if(p!=NULL)
    {
        InOrder(p->lchild);
        printf("%c",p->c);
        PreOrder(p->rchild);

    }
}

//后序遍历
void PostOrder(BiTree p)
{
    if(p!=NULL)
    {
        InOrder(p->lchild);
        PreOrder(p->rchild);
        printf("%c",p->c);

    }
}

//层次遍历就是怎么读入的就怎么读出
//按照人们看的最舒服的方式
//层次遍历,层序遍历,广度优先遍历
void LevelOrder(BiTree T)
{
    LinkQueue Q;//辅助队列
    InitQueue(Q);//初始化队列
    BiTree p;
    EnQueue(Q,T);//树根入队
    while(!IsEmpty(Q))
    {
        DeQueue(Q,p);//出队当前结点并打印
        putchar(p->c);
        if(p->lchild!=NULL) //入队左孩子
            EnQueue(Q,p->lchild);
        if(p->rchild!=NULL) //入队右孩子
            EnQueue(Q,p->rchild);
    }
}

int main(){
    BiTree pnew;//用来指向新申请的树节点
    //树里面每个节点都用,不是还有头结点的那种
    BiTree tree=NULL;//tree是指向树根的,代表树
    char c;
    ptag_t phead=NULL,ptail=NULL,listpnew=NULL,pcur;
    //abcdefghij
    while(scanf("%c",&c))
    {
        if(c=='\n')
        {
            break;//读取到换行就结束
        }
        //calloc申请的空间大小是两个参数的乘积,calloc的好处是申请了空间之后,并且进行初始化,就很好
        pnew=(BiTree)calloc(1,sizeof(BiTNode));
        pnew->c=c;
        //给队列节点申请空间
        listpnew= (ptag_t)calloc(1,sizeof(tag_t));
        listpnew->p=pnew;
        //如果是树的第一个节点
        if(NULL==tree)
        {
            tree=pnew;//树的根
            phead=listpnew;//队列头
            ptail=listpnew;//队列尾
            pcur=listpnew;
            continue;
        }else{
            ptail->pnext=listpnew;//新结点放入链表,通过尾插法
            ptail=listpnew;//ptail 指向队列尾部
            //接下来把b节点放到树中
            if(NULL==pcur->p->lchild)//如何把新结点放入树
            {
                pcur->p->lchild=pnew;//把新结点放到要插入结点的左孩子
            }else if(NULL==pcur->p->rchild)
            {
                pcur->p->rchild=pnew;//把新结点放到要插入结点的右孩子
                pcur=pcur->pnext;//左右都放了结点后,pcur 指向队列的下一个,当前左右孩子都有了,就下一个节点
            }
        }//pcur 始终指向要插入的结点的位置

    }
    printf("-------PreOrder--------\n");
    PreOrder(tree);
    printf("\n");
    printf("-------InOrder--------\n");
    InOrder(tree);
    printf("\n");
    printf("-------PostOrder--------\n");
    PostOrder(tree);
    printf("\n");
    printf("-------cengciOrder--------\n");
    LevelOrder(tree);
    return 0;
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值