特殊的二叉树显示

3 篇文章 0 订阅
3 篇文章 0 订阅

特殊的二叉树显示


前言

最终实现目标

(1)以二叉链表存储的二叉树中,每个结点所含的数据元素均为单字母,试按树状打印二叉树的输出结果。

      

                                    

一、实现思路是什么?

//输出二叉树并按照指定格式输出
//通过观察最终的输出结果可以发现,其输出结果是将二叉树按照类似于层序遍历的方式将二叉树的数据输出到矩阵中。
//其二叉树中每个结点的位置为(结点当前深度,中序遍历时的位置)

二、使用步骤

代码如下:

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

typedef char ElemType;//将char类型数据改名为ElemType

//定义二叉链表
typedef struct TreeNode 
{
    ElemType data; //定义数据类型
    struct TreeNode* leftNode;  //定义左结点
    struct TreeNode* rightNode; //定义右结点
};//定义为结构体指针(命名为TNode)

//定义矩阵
typedef struct Matrix {
    int m, n;
    int **Datas;
}matrix;

//创建矩阵函数
void Create_Matrix(Matrix *T, int M, int N)
{
    int i;
    T->Datas = (int**)malloc(M * sizeof(int*)); 
    for (i = 0; i < M; i++)
    {
       T->Datas[i] = (int*)malloc(N * sizeof(int));
    }
    T->m = M;
    T->n = N;
}

//初始化矩阵
void Init_Matrix(matrix &T, int m, int n)
{
    int i, j;
    Create_Matrix(&T, m, n); //为矩阵申请空间
    for(i = 0; i < m; i++)
    {
        for (j = 0; j < n; j++) 
        {
            T.Datas[i][j] = 1;
        }
        
    }

}

//递归,遍历前序顺序和中序顺序创建二叉树
TreeNode* CreateTree(ElemType* Pre, ElemType* In,int Pre_Start, int Pre_End,int In_Strat, int In_End)
{
    TreeNode* T;
    int i, LTree_Len, RTree_Len;

    T = (TreeNode*)malloc(sizeof(TreeNode));  //建立根结点 
    if (!T)
    {       
       exit(0);
    }

    T->data = Pre[Pre_Start];    //遍历前序存储的结点 
    T->leftNode = T->rightNode = NULL;    //初始化时置空左右孩子指针 

    i = In_Strat;
    while (In[i] != T->data)    //在中序序列中寻找根结点位置
        i++;

    //计算左右子树长度
    //即在定义前序后获取头字符即为根结点
    //在中序遍历中找到根节点的位置定义为i
    //i - 中序起点 = 左子树长度 | 中序终点 - i = 右子树长度
    LTree_Len = i - In_Strat;    //左子树长度 
    RTree_Len = In_End - i;    //右子树长度

    //因为中序的顺序结构特殊,会在计算过程中出现先对左子树遍历完全后右子树为空
    //此时的结构为左-根,导致计算时右子树长度为1进入错误的递归
    //因此设置特殊状态,即当数据为'\0'的时候结点地址置空
    if (T->data == '\0')
    {
        T = NULL;
    }
    else
    {
        //左子树存在
        if (LTree_Len)
        {
            //进入递归
            T->leftNode = CreateTree(Pre, In, Pre_Start + 1, Pre_Start + LTree_Len, In_Strat, i - 1);
        }
        else
        {
            //结点置空
            T->leftNode = NULL;
        }
        //右子树存在
        if (RTree_Len)
        {
            //进入递归
            T->rightNode = CreateTree(Pre, In, Pre_Start + LTree_Len + 1, Pre_End, i + 1, In_End);
        }
        else
        {
            //结点置空
            T->rightNode = NULL;
        }
    }
    return T;
}

//求二叉树的深度
int Get_Depth(TreeNode* TNode) 
{
    //定义h1,h2分别为左右子树的深度
    int h1, h2;

    //如果结点为空,表示结点不存在,深度为零
    if (TNode == NULL)
    {
        return 0;
    }
    else 
    {
        h1 = Get_Depth(TNode->leftNode);//遍历左子树获取左子树深度
        h2 = Get_Depth(TNode->rightNode);//遍历右子树获取右子树深度
        
        //对比左右子树深度,深度最大者为该二叉树的真实深度-1
        if (h1 > h2) 
        {
            return h1 + 1;
        }
        else 
        {
            return h2 + 1;
        }
    }
}

//递归后序遍历二叉树根左右 
void Display_Post(TreeNode* Tnode)
{
    //判断是否存在该结点
    if (Tnode)
    {
        if (Tnode->data == '\0')
        {
            Tnode = NULL;
        }
        else
        {
            //若存在该结点,输出该结点的数据,并进行递归
            Display_Post(Tnode->leftNode);
            Display_Post(Tnode->rightNode);
            printf("%c", Tnode->data);
        }
    }
}

//释放二叉树所有结点内存
void FreeTree(TreeNode* Tnode)
{
    if (Tnode) 
    {
        TreeNode* left = Tnode->leftNode, *right = Tnode->rightNode;
        free(Tnode);
        Tnode = NULL;
        FreeTree(left);
        FreeTree(right);
    }
}

//输出二叉树并按照指定格式输出
//通过观察最终的输出结果可以发现,其输出结果是将二叉树按照类似于层序遍历的方式将二叉树的数据输出到矩阵中。
//其二叉树中每个结点的位置为(结点当前深度,中序遍历时的位置)
void Outcome(ElemType* In, Matrix &M, TreeNode* Tnode, int Depth, int i)
{
    if (i <= Depth)//i为当前深度的指标,Depth则是该树的深度
    {
        TreeNode* LNode = Tnode->leftNode;
        TreeNode* RNode = Tnode->rightNode;
        int Size = 0;
        while (In[Size] != Tnode->data)    //在中序序列中寻找根结点位置
            Size++;
        if (LNode && RNode)
        {
            M.Datas[i][Size] = Tnode->data;
            i++;
            //递归
            Outcome(In, M, Tnode->leftNode, Depth, i);
            Outcome(In, M, Tnode->rightNode, Depth, i);
           
        }
        else if (LNode && !RNode)
        {
            M.Datas[i][Size] = Tnode->data;
            i++;
            Outcome(In, M, Tnode->leftNode, Depth, i);
        }
        else if (!LNode && RNode)
        {
            M.Datas[i][Size] = Tnode->data;
            i++;
            Outcome(In, M, Tnode->rightNode, Depth, i);
        }
        else if (!LNode && !RNode)
        {
            M.Datas[i][Size] = Tnode->data;
            i++;
        }
    }
}

//逆时针旋转矩阵
Matrix CCW_Matrix(Matrix& T)
{
    int M = T.n;
    int N = T.m;
    Matrix result;
    Init_Matrix(result, M, N);
    for (int i = M - 1, u = 0; i >= 0; i--, u++)
    {
        for (int j = 0, v = 0; j < N; j++, v++)
        {
            result.Datas[u][v] = T.Datas[j][i];
        }
    }

    return result;
}

int main()
{
    //获取输入的二叉树前序
    printf("请输入二叉树前序:");
    char A[999];
    gets_s(A);
    int Node_Count = strlen(A);//获取二叉树结点数量
    char* a = A;
    //获取输入的二叉树中序
    printf("请输入二叉树中序:");
    char B[999];
    gets_s(B);
    char* b = B;

    //创建二叉树
    TreeNode *TNode;
    TNode = CreateTree(a, b, 0, Node_Count, 0, Node_Count);
    printf("二叉树后序遍历的顺序为:");
    Display_Post(TNode);
    printf("\n");

    //获取二叉树深度
    int Depth = Get_Depth(TNode);
    
    //先将二叉树输入矩阵中
    Matrix Tree_Datas;
    Init_Matrix(Tree_Datas, Depth, Node_Count);
    Outcome(b, Tree_Datas, TNode, Depth, 0);

    //定义最后的输出矩阵
    Matrix result = CCW_Matrix(Tree_Datas); //将矩阵逆时针旋转90度获得最后结果
    printf("最终输出结果为:\n");
    for (int i = 0; i < Node_Count; i++)
    {
        for (int j = 0; j < Depth; j++)
        {
            printf("%c ", result.Datas[i][j]);
        }
        printf("\n");
    }
    

    //释放二叉树
    FreeTree(TNode);
    return 0;
}

总结

文章作者:KUST_CZY

萌新初学,请大佬多多指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值