树与二叉树的转换丨代码详解

前言:本文代码及解析以【双亲表示法的树】与【孩子兄弟表示法的二叉树】之间的转换为例。

  • 双亲表示法——树的每个结点储存结点的值以及它指向的父节点;
  • 孩子兄弟表示法——二叉树结点存储本身的值以及两个子节点,其中左孩子是该结点的首个孩子,右孩子是兄弟。如下图中,2的左孩子是5,右兄弟是3。
接下来将以这张图为例来完成代码的实现。
接下来我们将以这张图中的树和二叉树转换为例来完成代码的实现。

一、树与二叉树结构的定义

①树的定义

typedef struct TreeNode
{
    int data;
    struct TreeNode* parent;
} TreeNode;
typedef struct Tree
{
    TreeNode tns[MAX_SIZE];
    int r, n;
} Tree;

②二叉树的定义

typedef struct BiTreeNode
{
    int data;
    struct BiTreeNode* leftChild;
    struct BiTreeNode* rightBrother;
} BiTreeNode;
typedef struct BiTree
{
    BiTreeNode btns[MAX_SIZE];
    int r, n;
} BiTree;

二者的定义类似,其中MAX_SIZE限制了结点的最大数量,r代表根的位置,n代表结点的实际数量


二、程序的整体框架

 主函数:

int main()
{
    //1、传入parent数组
    int parent[10] = { -1, 0, 0, 0, 1, 1, 3, 6, 6, 6 };

    //2、创建树并打印
    Tree tree = createTree(parent);
    printf("\n树:\n");
    printTree(tree);

    //3、将树转换为二叉树并打印
    BiTree tree1 = treeToBiTree(tree);
    printf("\n转换为二叉树:\n");
    printBiTree(tree1);

    //4、将二叉树转换回树并打印
    Tree tree2 = biTreeToTree(tree1);
    printf("\n转换回树:\n");
    printTree(tree2);

    return 0;
}

自定义函数及功能:

Tree createTree(int parent[]);//用parent数组创建树
void printTree(Tree tree);//打印树
void findChild(BiTreeNode* root, Tree tree);//树转二叉树的辅助函数
BiTree treeToBiTree(Tree tree);//将树转换为二叉树
void printBiTree(BiTree bitree);//打印二叉树
void addChild(TreeNode* parent, BiTreeNode* child, Tree* tree);//二叉树转树的辅助函数
Tree biTreeToTree(BiTree bitree);//将二叉树转换为树

三、parent数组创建树

Tree createTree(int parent[])
{
    tree.r = 0;
    tree.n = 0;
    while (tree.n < 10)
    {
        tree.tns[tree.n].data = tree.n + 1;
        tree.tns[tree.n].parent = NULL;

        if (parent[tree.n] != -1)
        {
            tree.tns[tree.n].parent = &tree.tns[parent[tree.n]];
        }
        tree.n++;
    }
    return tree;
}

 parent[i]即第i个结点对应的双亲结点的位置


三、树转换为二叉树

BiTree treeToBiTree(Tree tree)
{
    bitree.r = 0;
    bitree.n = tree.n;
    for (int i = 0; i < bitree.n; i++)
    {
        bitree.btns[i].data = tree.tns[i].data;
        bitree.btns[i].leftChild = NULL;
        bitree.btns[i].rightBrother = NULL;
    }
    BiTreeNode* root = &bitree.btns[0];
    findChild(root, tree);
    return bitree;
}

 将树转换为二叉树的函数:将树的节点数据复制到二叉树的节点中,并将左子节点和右兄弟节点初始化为NULL。接着找到根节点并调用findChild函数来构建二叉树的结构。最后返回转换后的二叉树bitree。

void findChild(BiTreeNode* root, Tree tree)
{
    BiTreeNode* currentChild = NULL;
    for (int i = 0; i < tree.n; i++)
    {
        if (tree.tns[i].parent && tree.tns[i].parent->data == root->data)
        {
            BiTreeNode* newChild = &bitree.btns[i];
            if (currentChild == NULL)
            {
                root->leftChild = newChild;
            }
            else
            {
                currentChild->rightBrother = newChild;
            }
            currentChild = newChild;
            findChild(currentChild, tree);
        }
    }
}

如果一个结点的parent结点的值等于root结点的值,就将该结点currentChild作为root的左孩子;

i增加再进入循环时,root已经有左孩子,于是将第二个孩子接在左孩子的右兄弟上,将第二个孩子作为currentChild,以此类推;

同时利用递归找到所有结点的孩子。


四、二叉树转换回树

Tree biTreeToTree(BiTree bitree)
{
    tree2.r = 0;
    tree2.n = 0;
    addChild(NULL, &bitree.btns[0], &tree2);
    return tree;
}

首先对第二棵树进行初始化;

然后通过递归函数addChild实现每个结点与其双亲结点的连接。 

void addChild(TreeNode* parent, BiTreeNode* child, Tree* tree2)
{
    tree2->tns[tree2->n].data = child->data;
    tree2->tns[tree2->n].parent = parent;
    tree2->n++;

    if (child->leftChild != NULL)
    {
        addChild(&tree2->tns[tree2->n - 1], child->leftChild, tree2);
    }

    if (child->rightBrother != NULL)
    {
        addChild(parent, child->rightBrother, tree2);
    }
}

以左图的二叉树为例,首先将1的双亲赋值为NULL,1有左孩子,则进入递归;
第二次进入函数后,将2的双亲赋为1,2有左孩子5,则道理同上;
同时2有右孩子3,此时注意是把3的双亲赋为1,也就是2的双亲


五、树与二叉树的打印

5.1、信息的打印

打印树格式:

XX ->parent XX

void printTree(Tree tree)
{
    for (int i = 0; i < tree.n; i++)
    {
        if (tree.tns[i].parent != NULL)
        {
            printf("%d ->parent-> %d\n", tree.tns[i].data, tree.tns[i].parent->data);
        }
        else
        {
            printf("%d ->parent-> NULL\n", tree.tns[i].data);
        }
    }
}

打印二叉树格式:

XX:leftChild ->XX rightBrother ->XX

void printBiTree(BiTree bitree)
{
    for (int i = 0; i < bitree.n; i++)
    {
        printf("%2d:  ", bitree.btns[i].data);
        if (bitree.btns[i].leftChild != NULL)
        {
            printf("leftChild->%4d ", bitree.btns[i].leftChild->data);
        }
        else
        {
            printf("leftChild->NULL ");
        }
        if (bitree.btns[i].rightBrother != NULL)
        {
            printf("rightBrother->%4d ", bitree.btns[i].rightBrother->data);
        }
        else
        {
            printf("rightBrother->NULL ");
        }
        printf("\n");
    }
}

5.2、二叉树的遍历方法

递归/非递归(堆栈)/层次(队列)遍历方法合集丨代码详解icon-default.png?t=N7T8https://blog.csdn.net/qq_74315738/article/details/139021345

六、总结

综上,完整代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 20

//定义树结构
typedef struct TreeNode
{
    int data;
    struct TreeNode* parent;
} TreeNode;
typedef struct Tree
{
    TreeNode tns[MAX_SIZE];
    int r, n;
} Tree;
Tree tree;
Tree tree2;

//定义二叉树结构
typedef struct BiTreeNode
{
    int data;
    struct BiTreeNode* leftChild;
    struct BiTreeNode* rightBrother;
} BiTreeNode;
typedef struct BiTree
{
    BiTreeNode btns[MAX_SIZE];
    int r, n;
} BiTree;
BiTree bitree;

Tree createTree(int parent[]);//用parent数组创建树
void printTree(Tree tree);//打印树
void findChild(BiTreeNode* root, Tree tree);//树转二叉树的辅助函数
BiTree treeToBiTree(Tree tree);//将树转换为二叉树
void printBiTree(BiTree bitree);//打印二叉树
void addChild(TreeNode* parent, BiTreeNode* child, Tree* tree);//二叉树转树的辅助函数
Tree biTreeToTree(BiTree bitree);//将二叉树转换为树

int main()
{
    //1、传入parent数组
    int parent[10] = { -1, 0, 0, 0, 1, 1, 3, 6, 6, 6 };

    //2、创建树并打印
    Tree tree = createTree(parent);
    printf("\n树:\n");
    printTree(tree);

    //3、将树转换为二叉树并打印
    BiTree tree1 = treeToBiTree(tree);
    printf("\n转换为二叉树:\n");
    printBiTree(tree1);

    //4、将二叉树转换回树并打印
    Tree tree2 = biTreeToTree(tree1);
    printf("\n转换回树:\n");
    printTree(tree2);

    return 0;
}

Tree createTree(int parent[])
{
    tree.r = 0;
    tree.n = 0;
    while (tree.n < 10)
    {
        tree.tns[tree.n].data = tree.n + 1;
        tree.tns[tree.n].parent = NULL;

        if (parent[tree.n] != -1)
        {
            tree.tns[tree.n].parent = &tree.tns[parent[tree.n]];
        }
        tree.n++;
    }
    return tree;
}

void printTree(Tree tree)
{
    for (int i = 0; i < tree.n; i++)
    {
        if (tree.tns[i].parent != NULL)
        {
            printf("%d ->parent-> %d\n", tree.tns[i].data, tree.tns[i].parent->data);
        }
        else
        {
            printf("%d ->parent-> NULL\n", tree.tns[i].data);
        }
    }
}

void findChild(BiTreeNode* root, Tree tree)
{
    BiTreeNode* currentChild = NULL;
    for (int i = 0; i < tree.n; i++)
    {
        if (tree.tns[i].parent && tree.tns[i].parent->data == root->data)
        {
            BiTreeNode* newChild = &bitree.btns[i];
            if (currentChild == NULL)
            {
                root->leftChild = newChild;
            }
            else
            {
                currentChild->rightBrother = newChild;
            }
            currentChild = newChild;
            findChild(currentChild, tree);
        }
    }
}

BiTree treeToBiTree(Tree tree)
{
    bitree.r = 0;
    bitree.n = tree.n;
    for (int i = 0; i < bitree.n; i++)
    {
        bitree.btns[i].data = tree.tns[i].data;
        bitree.btns[i].leftChild = NULL;
        bitree.btns[i].rightBrother = NULL;
    }
    BiTreeNode* root = &bitree.btns[0];
    findChild(root, tree);
    return bitree;
}

void printBiTree(BiTree bitree)
{
    for (int i = 0; i < bitree.n; i++)
    {
        printf("%2d:  ", bitree.btns[i].data);
        if (bitree.btns[i].leftChild != NULL)
        {
            printf("leftChild->%4d ", bitree.btns[i].leftChild->data);
        }
        else
        {
            printf("leftChild->NULL ");
        }
        if (bitree.btns[i].rightBrother != NULL)
        {
            printf("rightBrother->%4d ", bitree.btns[i].rightBrother->data);
        }
        else
        {
            printf("rightBrother->NULL ");
        }
        printf("\n");
    }
}

void addChild(TreeNode* parent, BiTreeNode* child, Tree* tree2)
{
    tree2->tns[tree2->n].data = child->data;
    tree2->tns[tree2->n].parent = parent;
    tree2->n++;

    if (child->leftChild != NULL)
    {
        addChild(&tree2->tns[tree2->n - 1], child->leftChild, tree2);
    }

    if (child->rightBrother != NULL)
    {
        addChild(parent, child->rightBrother, tree2);
    }
}

Tree biTreeToTree(BiTree bitree)
{
    tree2.r = 0;
    tree2.n = 0;
    addChild(NULL, &bitree.btns[0], &tree2);
    return tree;
}

运行结果:

树:
1 ->parent-> NULL
2 ->parent-> 1
3 ->parent-> 1
4 ->parent-> 1
5 ->parent-> 2
6 ->parent-> 2
7 ->parent-> 4
8 ->parent-> 7
9 ->parent-> 7
10 ->parent-> 7

转换为二叉树:
 1:  leftChild->   2 rightBrother->NULL
 2:  leftChild->   5 rightBrother->   3
 3:  leftChild->NULL rightBrother->   4
 4:  leftChild->   7 rightBrother->NULL
 5:  leftChild->NULL rightBrother->   6
 6:  leftChild->NULL rightBrother->NULL
 7:  leftChild->   8 rightBrother->NULL
 8:  leftChild->NULL rightBrother->   9
 9:  leftChild->NULL rightBrother->  10
10:  leftChild->NULL rightBrother->NULL

转换回树:
1 ->parent-> NULL
2 ->parent-> 1
3 ->parent-> 1
4 ->parent-> 1
5 ->parent-> 2
6 ->parent-> 2
7 ->parent-> 4
8 ->parent-> 7
9 ->parent-> 7
10 ->parent-> 7

D:\Cfiles\DSweek8\Debug\DSweek8.exe (进程 18280)已退出,代码为 0。
按任意键关闭此窗口. . .

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是将一颗普通转换二叉树的C语言代码: ```c #include <stdio.h> #include <stdlib.h> typedef struct TreeNode { int data; struct TreeNode *firstChild; struct TreeNode *nextSibling; } TreeNode; typedef struct BinaryTreeNode { int data; struct BinaryTreeNode *left; struct BinaryTreeNode *right; } BinaryTreeNode; BinaryTreeNode* convert(TreeNode *root) { if (root == NULL) { return NULL; } BinaryTreeNode *binaryRoot = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode)); binaryRoot->data = root->data; binaryRoot->left = NULL; binaryRoot->right = NULL; if (root->firstChild != NULL) { binaryRoot->left = convert(root->firstChild); } if (root->nextSibling != NULL) { binaryRoot->right = convert(root->nextSibling); } return binaryRoot; } int main() { // 构造一颗普通 TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode)); root->data = 1; root->firstChild = (TreeNode *)malloc(sizeof(TreeNode)); root->firstChild->data = 2; root->firstChild->firstChild = (TreeNode *)malloc(sizeof(TreeNode)); root->firstChild->firstChild->data = 4; root->firstChild->firstChild->firstChild = NULL; root->firstChild->firstChild->nextSibling = NULL; root->firstChild->nextSibling = (TreeNode *)malloc(sizeof(TreeNode)); root->firstChild->nextSibling->data = 5; root->firstChild->nextSibling->firstChild = NULL; root->firstChild->nextSibling->nextSibling = NULL; root->nextSibling = (TreeNode *)malloc(sizeof(TreeNode)); root->nextSibling->data = 3; root->nextSibling->firstChild = NULL; root->nextSibling->nextSibling = NULL; // 将普通转换二叉树 BinaryTreeNode *binaryRoot = convert(root); return 0; } ``` 其中,`TreeNode` 表示普通的节点,包含一个数据域和两个指针域,分别指向第一个孩子和兄弟节点;`BinaryTreeNode` 表示二叉树的节点,包含一个数据域和两个指针域,分别指向左子和右子。 `convert` 函数接受一个普通的根节点作为参数,返回一个二叉树的根节点。在函数内部,我们先创建一个二叉树的根节点,将普通的根节点的数据域赋值给二叉树的根节点的数据域。然后,如果普通的根节点有第一个孩子,我们递归调用 `convert` 函数得到其左子,并将其赋值给二叉树的根节点的左子指针;如果普通的根节点有兄弟节点,我们递归调用 `convert` 函数得到其右子,并将其赋值给二叉树的根节点的右子指针。最后,返回二叉树的根节点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值