普通树转化成二叉树基本方法:
1、需要使用队列存储树的节点。
2、将根加入队列。
3、循环判断,队列不为空时。
4、循环体内,从队列中取出一个节点,遍历所有的孩子节点,并依次将他们加入到队列中。期间将其第一个子节点标为左孩子。将其他子节点标记为他们前面的兄弟节点的右孩子。(比如:a 下有 b c d三个子节点,循环之后,d成了c的右孩子,c成了b的右孩子,b是a的左孩子,建议画图理解)
上面是通俗的描述,真实的算法实现时,需要分别定义两棵树结构。下面结合代码进行描述。
#include <stdio.h>
#include <stdlib.h>
#define N 3 //定义每个节点的最大孩子数
#define M 9 //定义树中节点的个数
//下面进行结构体定义
struct TreeNode //普通树节点
{
char data;
struct TreeNode *childs[N]; //保存指针的数组
}; //结构体的分号不可缺少
typedef struct TreeNode TreeNode; //定义类型,这样定义之后,以后使用直
//接TreeNode *name;即可,不用加上struct(struct TreeNode *name;)
struct BTreeNode //二叉树结点
{
char data;
struct BTreeNode *lchild, *rchild; //结构体内的使用自身的时候
//,struct不可以省,包括上面的树、下面的队列定义
};
typedef struct BTreeNode BTreeNode;
//普通树的队列定义开始
struct QueueTree
{
int i, j; //指向数组内元素的游标
TreeNode **queue; //二维指针,与指针数组类似,不过需要动态分配空间
//此处使用前边定义好的结构,不需要struct
};
typedef struct QueueTree QueueTree;
QueueTree * initQueueTree() //初始化普通树队列
{
//分配一个队列空间
QueueTree *tree = (QueueTree *)malloc(sizeof(QueueTree));
//分配M个树节点指针空间
tree->queue = (TreeNode **)malloc(sizeof(TreeNode *)*M);
tree->i = 0;
tree->j = 0;
return tree;
}
void freeQueueTree(QueueTree *tree) //释放分配空间
{
free(tree->queue); //先分配先释放
free(tree);
}
void addQueueTree(QueueTree *tree, TreeNode *node) //加入队列
{
if(tree->j == M) //队列已满
return;
tree->queue[tree->j] = node;
tree->j++;
}
TreeNode * delQueueTree(QueueTree *tree)
{
if(tree->i == tree->j) //队列已空
return NULL;
TreeNode *node = tree->queue[tree->i];
tree->i++;
return node;
}
int emptyQueueTree(QueueTree *tree) //队列是否为空
{
return tree->i==tree->j; //1空
}
//二叉树队列定义开始,与上面类似,保证命名不重复
struct QueueBTree
{
int i, j;
BTreeNode **queue;
};
typedef struct QueueBTree QueueBTree;
QueueBTree * initQueueBTree()
{
//分配一个队列空间
QueueBTree *btree = (QueueBTree *)malloc(sizeof(QueueBTree));
//分配M个树节点指针空间
btree->queue = (BTreeNode **)malloc(sizeof(BTreeNode *)*M);
btree->i = 0;
btree->j = 0;
return btree;
}
void freeQueueBTree(QueueBTree *btree) //释放分配空间
{
free(btree->queue);
free(btree);
}
void addQueueBTree(QueueBTree *btree, BTreeNode *node) //加入队列
{
if(btree->j == M) //队列已满
return;
btree->queue[btree->j] = node;
btree->j++;
}
BTreeNode * delQueueBTree(QueueBTree *tree)
{
if(tree->i == tree->j) //队列已空
return NULL;
BTreeNode *node = tree->queue[tree->i];
tree->i++;
return node;
}
int emptyQueueBTree(QueueBTree *tree)
{
return tree->i==tree->j; //1空
}
//普通树转化成二叉树开始
BTreeNode * transform(TreeNode *root)
{
if(root == NULL)
return NULL;
//先分配根节点空间,构造二叉树的根节点
BTreeNode *broot = NULL;
broot = (BTreeNode *)malloc(sizeof(BTreeNode));
broot->data = root->data; //复制根节点数据
broot->lchild = broot->rchild = NULL; //指针置空
//初始普通树、二叉树队列,并将他们的根节点分别加入对应队列
QueueTree *queue = initQueueTree();
QueueBTree *bqueue = initQueueBTree();
addQueueTree(queue, root);
addQueueBTree(bqueue, broot);
//循环判断,当普通树的队列不空时
while(emptyQueueTree(queue) == 0)
{
//从两个队列中分别取出一个节点
TreeNode *node = delQueueTree(queue);
BTreeNode *btreeNode = delQueueBTree(bqueue);
int i;
BTreeNode *former = NULL;
//遍历普通树节点的所有孩子节点,将孩子加入普通树队列
for(i=0; i<N; i++)
{
if(node->childs[i] != NULL)
{
//每遍历一个孩子节点,就分配新的二叉树节点空间
BTreeNode *bnode =
(BTreeNode *)malloc(sizeof(BTreeNode));
//指针置空
bnode->lchild = bnode->rchild = NULL;
//复制数据
bnode->data = node->childs[i]->data;
//二叉树结点指针调整
if(i == 0)
{
//第一个孩子节点作为二叉树上层节点左孩子
btreeNode->lchild = bnode;
former = bnode;
}
else
{
//后面的孩子节点作为同层前面节点的右孩子
former->rchild = bnode;
former = bnode;
}
addQueueTree(queue, node->childs[i]);
addQueueBTree(bqueue, bnode);
}
}
}
freeQueueTree(queue); //空间释放
freeQueueBTree(bqueue);
return broot;
}
//测试开始
TreeNode * initTree() //构造一棵普通树
{
TreeNode *root = (TreeNode *)malloc(sizeof(TreeNode));
root->data = 'a';
TreeNode *p1 = (TreeNode *)malloc(sizeof(TreeNode));
p1->data = 'b';
TreeNode *p2 = (TreeNode *)malloc(sizeof(TreeNode));
p2->data = 'c';
TreeNode *p3 = (TreeNode *)malloc(sizeof(TreeNode));
p3->data = 'd';
TreeNode *p4 = (TreeNode *)malloc(sizeof(TreeNode));
p4->data = 'e';
TreeNode *p5 = (TreeNode *)malloc(sizeof(TreeNode));
p5->data = 'f';
TreeNode *p6 = (TreeNode *)malloc(sizeof(TreeNode));
p6->data = 'g';
TreeNode *p7 = (TreeNode *)malloc(sizeof(TreeNode));
p7->data = 'h';
TreeNode *p8 = (TreeNode *)malloc(sizeof(TreeNode));
p8->data = 'i';
root->childs[0] = p1;
root->childs[1] = p2;
root->childs[2] = p3;
p1->childs[0] = p4;
p1->childs[1] = p5;
p1->childs[2] = p6;
p2->childs[0] = NULL;
p2->childs[1] = NULL;
p2->childs[2] = NULL;
p3->childs[0] = p7;
p3->childs[1] = p8;
p3->childs[2] = NULL;
int i;
for(i=0; i<N; i++)
{
p4->childs[i] = NULL;
p5->childs[i] = NULL;
p6->childs[i] = NULL;
p7->childs[i] = NULL;
p8->childs[i] = NULL;
}
return root;
}
void destroyTree(TreeNode *root) //释放树空间
{
if(root == NULL)
return;
if(root->childs[0] == NULL && root->childs[1] == NULL && root->childs[2] == NULL)
free(root);
else
{
if(root->childs[0] != NULL)
destroyTree(root->childs[0]);
if(root->childs[1] != NULL)
destroyTree(root->childs[1]);
if(root->childs[2] != NULL)
destroyTree(root->childs[2]);
}
}
void iterator(TreeNode *root) //层序遍历该树
{
if(root == NULL)
return;
QueueTree *queue = initQueueTree();
addQueueTree(queue, root);
while(emptyQueueTree(queue) == 0)
{
TreeNode *p = delQueueTree(queue);
printf("%c ", p->data);
int i;
for(i=0; i<N; i++)
{
if(p->childs[i] != NULL)
{
addQueueTree(queue, p->childs[i]);
}
}
}
freeQueueTree(queue);
}
void preOrder(BTreeNode *root) //二叉树前序遍历
{
if(root == NULL)
return;
printf("%c ", root->data);
preOrder(root->lchild);
preOrder(root->rchild);
}
void destroyBTree(BTreeNode *root) //二叉树空间释放
{
if(root == NULL)
return;
if(root->lchild == NULL && root->rchild == NULL)
free(root);
else
{
if(root->lchild != NULL)
destroyBTree(root->lchild);
if(root->rchild != NULL)
destroyBTree(root->rchild);
}
}
int main()
{
TreeNode *root = initTree();
iterator(root); //层序输出普通树
printf("\n");
BTreeNode *broot = transform(root);
preOrder(broot); //前序输出二叉树
printf("\n");
destroyBTree(broot);
destroyTree(root);
return 0;
}
注意:当函数的返回值类型为指针时,如果忘记写return语句,编译可以通过,运行时会自动终止。同时需要小心内存分配的问题