考研408 2014年第41题(二叉树带权路径长度【WPL】)

WPL=2×2+2×3+2×4+2×7=32

function.h(结构体):

//
// Created by legion on 2024/3/5.
//

#ifndef INC_14_4_TREE_FUNCTION_H
#define INC_14_4_TREE_FUNCTION_H
#include <stdio.h>
#include <stdlib.h>

typedef int BiElemType;
typedef struct BiTNode{
    BiElemType weight;//直接拿字符的ASCII值来计算即可
    struct BiTNode *lchild;
    struct BiTNode *rchild;
}BiTNode,*BiTree;

//tag结构体是辅助队列使用的 队列是由链表实现的
typedef struct tag{
    BiTree p;//树的某一个结点的地址值
    struct tag *pnext;
}tag_t,*ptag_t;//这个链表结构体类型tag_t 为什么和结构体名不一致

//辅助队列 的结构体
typedef BiTree ElemType;
typedef struct LinkNode{
    ElemType data;//
    struct LinkNode *next;
}LinkNode;
typedef struct{//队列结构体
    LinkNode *front,*rear;//链表头 链表尾 可以称为队头 队尾
}LinkQueue;//先进先出


void InitQueue(LinkQueue &Q);
//入队

bool IsEmpty(LinkQueue Q);

void EnQueue(LinkQueue &Q,ElemType x);//不修改故不引用
//出队
bool DeQueue(LinkQueue &Q,ElemType &x);//出队后有可能发生real指向头指针 Q有可能发生改变 所以引用

#endif //INC_14_4_TREE_FUNCTION_H

queue.cpp(函数):

//
// Created by legion on 2024/3/7.
//
#include "function.h"

//队列的初始化,使用的是带头结点的链表来实现的
void InitQueue(LinkQueue &Q)
{
    Q.front=Q.rear=(LinkNode*)malloc(sizeof(LinkNode));
    Q.front->next==NULL;
}

//判断队列是否为空
bool IsEmpty(LinkQueue Q)
{
    return Q.rear==Q.front;
}

//入队
void EnQueue(LinkQueue &Q,ElemType x)//不修改故不引用
{
    LinkNode *pnew=(LinkNode*)malloc(sizeof(LinkNode));
    pnew->data=x;
    pnew->next=NULL;//要让next为NULL
    Q.rear->next=pnew;//尾指针的next指向pnew,因为从尾部入队
    Q.rear=pnew;//rear要指向新的尾部

}

//出队
bool DeQueue(LinkQueue &Q,ElemType &x)//出队后有可能发生real指向头指针 Q有可能发生改变 所以引用
{
    if(Q.rear==Q.front)//队列为空
    {
        return false;
    }
    LinkNode* q=Q.front->next;//拿到第一个结点,存入q
    x=q->data;
    Q.front->next=q->next;//让第一个结点断链
    if(Q.rear==q)//链表只剩余一个结点时,被删除后,要改变rear
    {
        Q.rear=Q.front;
    }
    free(q);
    return true;

}

main.cpp:

#include "function.h"

//int wpl=0;
//前序遍历函数,也叫先序遍历,也是深度优先遍历
int PreOrder(BiTree p,int deep)//只是遍历 即只是读,不会改变树根
{//这个p的类型是 树的结构体 不是之前的p指针
    static int wpl=0;//静态局部变量,存储在数据段内,所以只会初始化一次
    //while循环中只会走一次 ,区别于全局变量 只能在函数内访问,所以最后要return出去
    if(p!=NULL)
    {
//        printf("ele%c--%d\n", p->c,deep);
        if(p->lchild==NULL&&p->rchild==NULL)
        {
            wpl=wpl+p->weight*deep;

        }
        PreOrder(p->lchild,deep+1);//函数嵌套 打印左子树
        PreOrder(p->rchild,deep+1);//函数嵌套 打印右子树
    }
    return wpl;

}
//中序遍历
void InOrder(BiTree p)//只是遍历 即只是读,不会改变树根
{//这个p的类型是 树的结构体 不是之前的p指针
    if(p!=NULL)
    {
        InOrder(p->lchild);//函数嵌套 打印左子树
        printf("%c", p->weight);
        InOrder(p->rchild);//函数嵌套 打印右子树
    }
}
//后续遍历
void PostOrder(BiTree p)//只是遍历 即只是读,不会改变树根
{//这个p的类型是 树的结构体 不是之前的p指针
    if(p!=NULL)
    {
        PostOrder(p->lchild);//函数嵌套 打印左子树
        PostOrder(p->rchild);//函数嵌套 打印右子树
        printf("%c", p->weight);
    }
}

//层序遍历
//层次遍历 层序遍历 广度优先遍历
void LevelOrder(BiTree T)//树的结构体指针 有左孩子和有孩子
{
    LinkQueue Q;//定义一个队列Q
    InitQueue(Q);//初始化队列Q 队头等于队尾  next指针指向NULL
    BiTree p;//存储出队的结点 p为一个树的结构体指针
    EnQueue(Q,T);//把根入队
    while(!IsEmpty(Q))//队列不为空才进入到循环当中
    {
        DeQueue(Q,p);
        putchar(p->weight);//等价于printf("%c",c);
        if(p->lchild)
        {
            EnQueue(Q,p->lchild);//左孩子不为空 入队左孩子
        }
        if(p->rchild)
        {
            EnQueue(Q,p->rchild);
        }
    }


}

int main() {
    BiTree pnew;//用来指向新申请的树结点 结构体指针类型
    BiTree tree=NULL;//tree是指向树根的,代表树
    char c;
    //定义队列 phead是队列头ptail是队列尾 listpnew指向新结点 pcur是指向当前父结点
    ptag_t phead=NULL,ptail=NULL,listpnew=NULL,pcur;
    //输入abcdefghij
    while(scanf("%c",&c))
    {
        if(c=='\n')
        {
            break;//读取换行结束
        }
        //calloc申请的空间大小是两个参数直接相乘,并对空间进行初始化,赋值为0
        pnew= (BiTree)calloc(1,sizeof(BiTNode));
        pnew->weight=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指向队列尾部
        }//pcur始终指向要插入的结点的位置
        if(NULL==pcur->p->lchild)
        {
            pcur->p->lchild=pnew;//把新结点放到要插入结点的左边
        } else if(NULL==pcur->p->rchild)
        {
            pcur->p->rchild=pnew;//把新结点放到要插入结点的右边
            pcur=pcur->pnext;//左右都放了结点后,pcur指向队列下一个
        }
    }

 //14.5二叉树的前序中序后续遍历
    printf("------------PreOrder------------\n");
//    printf("\n------------InOrder------------\n");
//    InOrder(tree);
//    printf("\n------------PostOrder------------\n");
//    PostOrder(tree);
//    printf("\n------------LevelOrder------------\n");
//    LevelOrder(tree);
    printf("wpl=%d\n",PreOrder(tree,0));//叶子结点层数为3时其实际路径为2
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陆小果不会写代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值