/**
*    实验题目:
*        求二叉树中从根结点到叶子结点的路径
*    实验目的:
*        掌握二叉树遍历算法的应用,熟练使用先序、中序、后序3种递归
*    和非递归遍历算法以及层次遍历算法进行二叉树问题求解。
*    实验内容:
        设计程序,完成如下功能:
*    1、采用先序遍历方法输出所有从叶子结点到根结点的逆路径
*    2、采用先序遍历方法输出第一条最长的逆路径
*    3、采用后序非递归遍历方法输出所有从叶子结点到根结点的逆路径
*    4、采用层次遍历方法输出所有从叶子结点到根结点的逆路径
*/

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

#define MAX_SIZE 100

typedef char ElemType;
typedef struct node
{
    ElemType data; // 数据元素
    struct node *lchild; // 指向左孩子结点
    struct node *rchild; // 指向右孩子结点
}BTNode; // 声明二叉链结点类型

/*-------------由括号表示串str创建二叉链b-----------------*/
static void create_btree(BTNode *&b, char *str) // 创建二叉树(形参b:指针的引用)
{
    BTNode *p;
    BTNode *St[MAX_SIZE]; // 定义一个顺序栈
    int k;
    int j = 0;
    int top = -1; // 栈顶指针初始化
    char ch;

b = NULL; // 建立的二叉树初始时为空
    ch = str[j]; // 取第一个字符
    while(ch != '\0') // str未扫描完时循环
    {
        switch(ch)
        {
        case '(': // 开始处理左子树
            top++;
            St[top] = p;
            k = 1;
            break;
        case ')': // 子树处理完毕
            top--;
            break;
        case ',': // 开始处理右子树
            k = 2;
            break;
        default:
            p = (BTNode *)malloc(sizeof(BTNode)); // 动态分配结点p的存储空间
            p->data = ch;
            p->lchild = p->rchild = NULL;
            if(b == NULL) // 若b为空,p置为二叉树的根结点
                b = p;
            else // 已建立二叉树根结点
            {
                switch(k)
                {
                case 1:
                    St[top]->lchild = p;
                    break;
                case 2:
                    St[top]->rchild = p;
                    break;
                }
            }
            break;
        }
        // 取下一个字符
        j++;
        ch = str[j];
    }
}

/*--------------------------以括号表示法输出二叉树b----------------------*/
// "A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))"
static void disp_btree(BTNode *b)
{
    if(b != NULL)
    {
        printf("%c", b->data);
        if(b->lchild != NULL || b->rchild != NULL)
        {
            printf("("); // 有孩子结点时才输出(
            disp_btree(b->lchild); // 递归处理左子树
            if(b->rchild != NULL) // 有右孩子结点时才输出,
                printf(",");
            disp_btree(b->rchild); // 递归处理右子树
            printf(")"); // 有孩子结点时才输出)
        }
    }
}

/*--------------------------释放二叉树b的所有结点----------------------*/
static void destroy_btree(BTNode *&b) // 销毁二叉树(形参b:指针的引用)
{
    if(b != NULL)
    {
        destroy_btree(b->lchild);
        destroy_btree(b->rchild);
        free(b);
    }
}

/*--------------------------返回b结点的左孩子结点指针----------------------*/
static BTNode *left_child_node(BTNode *b)
{
    return b->lchild;
}

/*--------------------------返回b结点的右孩子结点指针----------------------*/
static BTNode *right_child_node(BTNode *b)
{
    return b->rchild;
}

/*--------------------------返回data域为x的结点指针----------------------*/
static BTNode *find_node(BTNode *b, ElemType x) // 查找值为x的结点
{
    BTNode *p;

if(b == NULL)
        return NULL;
    else if(b->data == x)
        return b;
    else
    {
        p = find_node(b->lchild, x);
        if(p != NULL)
            return p;
        else
            return find_node(b->rchild, x);
    }
}

/*--------------------------求二叉树b的深度----------------------*/
static int btree_height(BTNode *b)
{
    int left_child_height, right_child_height;

if(b == NULL) // 空树的深度为0
        return 0;
    else
    {
        // 求左子树的深度
        left_child_height = btree_height(b->lchild);
        // 求右子树的深度
        right_child_height = btree_height(b->rchild);

return (left_child_height > right_child_height) ? (left_child_height + 1) : (right_child_height + 1);
    }
}

/*--------------------------采用先序遍历方法输出所有从叶子结点到根结点的逆路径----------------------*/
static void all_path1(BTNode *b, ElemType path[], int path_len)
{
    int i;

if(b == NULL)
        return;

if(b->lchild == NULL && b->rchild == NULL) // b为叶子结点
    {
        printf("   %c到根结点逆路径: %c->", b->data, b->data);
        for(i = path_len - 1; i > 0; i--) // 逆序输出
            printf("%c->", path[i]);
        printf("%c\n", path[0]); // 输出根结点A
    }
    else
    {
        path[path_len] = b->data; // 将当前结点放入路径中
        path_len++; // 路径长度增1
        all_path1(b->lchild, path, path_len); // 递归扫描左子树
        all_path1(b->rchild, path, path_len); // 递归扫描右子树
    }
}

/*--------------------------采用先序遍历方法输出第一条最长的逆路径----------------------*/
static void long_path1(BTNode *b, ElemType path[], int path_len, ElemType long_path[], int &long_path_len) // 引用long_path_len带回最长路径长度
{
    int i;

if(b == NULL)
    {
        if(path_len > long_path_len) // 若当前路径更长,将路径保存在long_path中
        {
            for(i = path_len - 1; i >= 0; i--) // 逆序保存到long_path
                long_path[i] = path[i];
            long_path_len = path_len; // 记录最长路径长度
        }
    }
    else
    {
        path[path_len] = b->data; // 将当前结点放入路径中
        //printf("path[%d] = %c\n", path_len, path[path_len]);
        path_len++; // 路径长度增1
        long_path1(b->lchild, path, path_len, long_path, long_path_len); // 递归扫描左子树
        long_path1(b->rchild, path, path_len, long_path, long_path_len); // 递归扫描右子树
    }
}

/*--------------------------采用后序(左、右、根)非递归遍历方法输出所有从叶子结点到根结点的逆路径----------------------*/
static void all_path2(BTNode *b)
{
    BTNode *st[MAX_SIZE]; // 定义一个顺序栈st
    int top = -1; // 栈顶指针初始化
    BTNode *p;
    BTNode *r;
    bool flag;

p = b; // p->A
    do
    {
        while(p != NULL) // 扫描结点p的所有左下结点并进栈
        {
            top++;
            st[top] = p; // 结点p进栈
            p = p->lchild; // 移动到左孩子
        }
        r = NULL; // r指向刚刚访问的结点,初始时为空
        flag = true; // flag为真表示正在处理栈顶结点
        while(top > -1 && flag) // 栈不空且flag为真时循环
        {
            p = st[top]; // 取出当前的栈顶结点p
            if(p->rchild == r) // 若结点p的右孩子为空或者为刚刚访问过的结点
            {
                if(p->lchild == NULL && p->rchild == NULL) // 若为叶子结点
                {
                    // 输出栈中所有结点值
                    printf("   %c到根结点逆路径: ", p->data);
                    for(int i = top; i > 0; i--)
                        printf("%c->", st[i]->data);
                    // 输出根结点
                    printf("%c\n", st[0]->data);
                }
                top--; // 退栈
                r = p; // r指向刚访问过的结点
            }
            else
            {
                p = p->rchild; // 转向处理其右子树
                flag = false; // 表示当前不是处理栈顶结点
            }
        }
    }while(top > -1); // 栈不空时循环
}

typedef struct snode
{
    BTNode *node; // 存放当前结点指针
    int parent; // 存放双亲结点在队列中的位置
}snode; // 声明顺序队列结点类型

/*--------------------------采用层次遍历方法输出所有从叶子结点到根结点的逆路径----------------------*/
static void all_path3(BTNode *b)
{
    snode qu[MAX_SIZE]; // 定义顺序队列
    int que_front, que_rear; // 定义队头和队尾指针
    int pos;

que_front = que_rear = -1; // 设置队列为空队列
    que_rear++;
    qu[que_rear].node = b; // 根结点指针进入队列
    qu[que_rear].parent = -1; // 根结点没有双亲结点

while(que_front < que_rear) // 队列不为空时循环
    {
        que_front++;
        b = qu[que_front].node; // 队头出队列
        printf("   从队头位置que_front = [%d], 出队元素[%c]\n", que_front, b->data);
        if(b->lchild == NULL && b->rchild == NULL) // b为叶子结点
        {
            /*-----------------输出叶子结点信息---------------------*/
            printf("   %c到根结点逆路径: \n", b->data);
            pos = que_front;
            printf("   出队列位置 = %d: \n", pos);
            printf("   %c的双亲parent = %d\n", b->data, qu[pos].parent);
            /*------------------------------------------------------*/
            while(qu[pos].parent != -1)
            {
                printf("%c->", qu[pos].node->data); // 输出结点(叶子结点和非根结点)
                pos = qu[pos].parent; // 更新pos的值
            }
            printf("%c\n", qu[pos].node->data); // 最后输出根结点
        }
        if(b->lchild != NULL) // 若有左孩子,将其进入队列
        {
            que_rear++;
            qu[que_rear].node = b->lchild;
            qu[que_rear].parent = que_front;
        }
        if(b->rchild != NULL) // 若有右孩子,将其进入队列
        {
            que_rear++;
            qu[que_rear].node = b->rchild;
            qu[que_rear].parent = que_front;
        }
    }
}

int main(int argc, char *argv[])
{
    BTNode *b;
    ElemType path[MAX_SIZE];
    ElemType long_path[MAX_SIZE];
    int i;
    int long_path_len = 0;

create_btree(b, "A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))");
    printf("二叉树b: ");
    disp_btree(b);
    printf("\n");
    printf("先序遍历方法:\n");
    all_path1(b, path, 0);
    long_path1(b, path, 0, long_path, long_path_len);
    printf("   第一条最长逆路径长度: %d\n", long_path_len);
    printf("   第一条最长逆路径: ");
    for(i = long_path_len - 1; i >= 0; i--)
        printf("%c ", long_path[i]);
    printf("\n");
    printf("后序非递归遍历方法:\n");
    all_path2(b);
    printf("层次遍历方法:\n");
    all_path3(b);

destroy_btree(b);

return 0;
}
测试结果:

二叉树b: A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))
先序遍历方法:
   D到根结点逆路径: D->B->A
   J到根结点逆路径: J->H->E->B->A
   L到根结点逆路径: L->K->H->E->B->A
   N到根结点逆路径: N->M->K->H->E->B->A
   F到根结点逆路径: F->C->A
   I到根结点逆路径: I->G->C->A
   第一条最长逆路径长度: 7
   第一条最长逆路径: N M K H E B A
后序非递归遍历方法:
   D到根结点逆路径: D->B->A
   J到根结点逆路径: J->H->E->B->A
   L到根结点逆路径: L->K->H->E->B->A
   N到根结点逆路径: N->M->K->H->E->B->A
   F到根结点逆路径: F->C->A
   I到根结点逆路径: I->G->C->A
层次遍历方法:
   D到根结点逆路径: D->B->A
   F到根结点逆路径: F->C->A
   I到根结点逆路径: I->G->C->A
   J到根结点逆路径: J->H->E->B->A
   L到根结点逆路径: L->K->H->E->B->A
   N到根结点逆路径: N->M->K->H->E->B->A

求二叉树中从根结点到叶子结点的路径相关推荐

  1. 一棵二叉树中总共有70个叶子结点与80个度为1的结点,则该二叉树中的总结点数为多少个?

    二叉树就是说一个结点下面可能有两个子结点(度为2),也可能有一个子结点(度为1),或者没有子结点(度为0,也叫叶子结点) 那么在这棵树中只可能出现三种情况:度为2,度为1,度为0(叶子结点).不可能出 ...

  2. 每天一道LeetCode-----以字符串的形式输出二叉树所有从根节点到叶子节点的路径

    Binary Tree Paths 原题链接Binary Tree Paths 将二叉树中所有从根节点到叶子节点的路径以字符串的形式输出出来 直接遍历即可,注意只有左右子节点都是空节点时才叫叶子节点 ...

  3. 【LeetCode 剑指offer刷题】树题19:8 二叉树中序遍历的下一个结点

    [LeetCode & 剑指offer 刷题笔记]目录(持续更新中...) 8 二叉树中序遍历的下一个结点 题目描述 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注 ...

  4. 二叉树的进阶操作---(求二叉树中所有结点个数,求叶子结点个数,求第k层结点个数;在二叉树中查找某一结点;层序遍历;判断是否为完全二叉树)

    typedef struct TreeNode {struct TreeNode *left;struct TreeNode *right;char val; }TreeNode;typedef st ...

  5. Java创建二叉树,并使用递归算法求二叉树中叶子结点的数目

    问题描述 创建二叉树,并使用递归算法求二叉树中叶子结点的数目 输入 输入一个用'.'来标明空子树的先根遍历序列,如ABD-EH-CF.I-G- 输出 叶子结点的个数 存储结构 二叉树 算法的基本思想 ...

  6. 二叉树题目----4 前序遍历重构二叉树 AND 求二叉树中所有结点的个数

    前序遍历重构二叉树 思路 整个二叉树用数组存储 因为先序遍历它先遍历根,再遍历左,左边没有跑完是不会去遍历右边的,所以遍历左子树,就是数组元素每回向后一个,个数-1 遍历右边时,就是数组起始位置+左子 ...

  7. 找二叉树根节点到叶子结点最长路径

    void Findpath(BiTree T){//后序遍历法寻找从根节点到叶子结点最长路径BiTree stack[MaxSize],path[MaxSize],p=T,r;int top=-1,m ...

  8. 【编程题目】求二叉树中节点的最大距离

    第 11 题(树) 求二叉树中节点的最大距离... 如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的, 我们姑且定义"距离"为两节点之间边的个数. 写一个程序, 求一棵二 ...

  9. 剑指offer之求二叉树中两个节点的最低共同父节点

    1 问题 求二叉树中俩个节点的最低共同父节点,比如二叉树如下 42 61 3 5 7 比如节点1和3两个节点的最低共同父节点是2,节点3和5两个节点的最低共同父节点是4,节点5和6两个节点的最低共同父 ...

最新文章

  1. 2021 年度热门技术书单提前公开,这些好书藏不住了
  2. 盘丝洞服务器维护,9月27日“盘丝洞”等服务器停机更新
  3. c语言链表把多少分以上打出来,大神帮我看一下怎么输入输出一个链表,我输入了但是没输出啊...
  4. python回复qq消息_自动给qq好友发消息
  5. linux用户的配置文件保存在哪里,使用配置文件(.settings、.config)存储应用程序配置...
  6. rsync同步工具学习笔记
  7. STM32 NVIC中断
  8. linux定时任务生效_Linux 添加定时任务
  9. python中高阶函数与装饰器(3)
  10. 为什么产品经理总被吐槽是”水货“
  11. 中科微GPS模块使用教程 ATGM332D ATGM336H GSP模块 单片机程序 C程序
  12. TRUNK 的介绍和配置
  13. 谈谈自己对做软件开发这一行业的想法
  14. 百度地图 LBS API 使用
  15. 每日一学18——凉鞋的简易有限状态机
  16. (原創) 如何將16進位的ACSII值轉成相對應的字元? (C/C++) (C)
  17. INSTALL_FAILED_NO_MATCHING_ABIS 的解决办法
  18. C++各种运行时错误
  19. 尚学堂lucene项目精讲视频共17讲
  20. C语言没学好,C++听不懂,怎么办?

热门文章

  1. SAP系统中---命令字段
  2. SDK 和 API 的区别,你都知道吗?
  3. python函数的装饰器
  4. 营收恢复加速增长,盐津铺子上演自我升级“好戏”
  5. 图片旋转、无限滚动、文字跳动
  6. conda配置中科大源
  7. Description Based Text Classification with Reinforcement Learning
  8. 抓紧收藏,自媒体人必备的热点工具,让你高效运营自媒体
  9. 股票期货涨跌幅价格计算器
  10. Linux下部署lvs+keepalived实现高可用负载均衡