前言:本文代码及解析以【双亲表示法的树】与【孩子兄弟表示法的二叉树】之间的转换为例。
- 双亲表示法——树的每个结点储存结点的值以及它指向的父节点;
- 孩子兄弟表示法——二叉树结点存储本身的值以及两个子节点,其中左孩子是该结点的首个孩子,右孩子是兄弟。如下图中,2的左孩子是5,右兄弟是3。
![接下来将以这张图为例来完成代码的实现。](https://img-blog.csdnimg.cn/direct/a5661b875c964e2ea54dcca749b74bf8.bmp)
一、树与二叉树结构的定义
①树的定义
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、二叉树的遍历方法
递归/非递归(堆栈)/层次(队列)遍历方法合集丨代码详解https://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。
按任意键关闭此窗口. . .