题目:二叉树的镜像
在完成此题目时,具体的测试要求见下面。
先说下完成此题目的感受:刚开始在《剑指Offer》这本书上看到这个题目的时候,感觉这个题目比较简单:就是将二叉树中的非叶子节点的左节点和右节点进行交换即可,但是从编码实现来看,有如下几个问题需要我们额外注意
1)用什么样的数据结构来保存树的节点是需要我们考虑的:采用数组来作为保存二叉树节点的数据结构
2)算法的实现好写,但是测试代码不好写,真的
/*二叉树的镜像
输入:
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000,n代表将要输入的二叉树节点的个数(节点从1开始编号)。接下来一行有n个数字,代表第i个二叉树节点的元素的值。接下来有n行,每行有一个字母Ci。
Ci=’d’表示第i个节点有两子孩子,紧接着是左孩子编号和右孩子编号。
Ci=’l’表示第i个节点有一个左孩子,紧接着是左孩子的编号。
Ci=’r’表示第i个节点有一个右孩子,紧接着是右孩子的编号。
Ci=’z’表示第i个节点没有子孩子。
输出:
对应每个测试案例,
按照前序输出其孩子节点的元素值。
若为空输出NULL。
样例输入:
7
8 6 10 5 7 9 11
d 2 3
d 4 5
d 6 7
z
z
z
z
样例输出:
8 10 11 9 6 7 5
*/
/*
思路:通过画图我们可以看到,二叉树的镜像就是将非叶子节点的左节点和右节点进行交换即可
注意:采用数组来作为保存二叉树节点的数据结构
测试样例:
1)一般的二叉树(完成树)
2)非完全树(包含两种情况:一种是有的节点只有左子树、有的节点只有右子数)
3)只有一个节点的树
4)特殊的输入
*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//树的节点
//由于节点是保存在数组中,因此,每个节点的pLeftChild、pRightChild为左右两个节点在节点数组中的下标
typedef int ElementType;
typedef struct TreeNode{
ElementType mValue;
int pLeftChild;
int pRightChild;
}TreeNode;
/*
参数的说明
@param pNode:树节点的头指针
@param index:节点在节点数组中的下标
*/
void mirrorBinaryTree(TreeNode *pNode,int index){
if(pNode==NULL){
return;
}
if(index==-1){
return;
}
if(pNode[index].pLeftChild==-1&&pNode[index].pRightChild==-1){//只有一个节点
return;
}
//交换此节点的左右节点
int temp=pNode[index].pLeftChild;
pNode[index].pLeftChild=pNode[index].pRightChild;
pNode[index].pRightChild=temp;
if(pNode[index].pLeftChild!=-1){
mirrorBinaryTree(pNode,pNode[index].pLeftChild);
}
if(pNode[index].pRightChild!=-1){
mirrorBinaryTree(pNode,pNode[index].pRightChild);
}
}
int j=0;
void saveValueByPreTraversal(TreeNode *pNode,int index,int *preTraversal,int len){
if(pNode==NULL){
printf("return!!");
return;
}
if(index!=-1&&j<len){
preTraversal[j++]=pNode[index].mValue;
//printf("%d",pNode[index].mValue);
if(pNode[index].pLeftChild!=-1){
saveValueByPreTraversal(pNode,pNode[index].pLeftChild,preTraversal,len);
}
if(pNode[index].pRightChild!=-1){
saveValueByPreTraversal(pNode,pNode[index].pRightChild,preTraversal,len);
}
}
}
int main(void){
//在得到二叉树的镜像的之前,我们需要创建一个树
int n;
while(scanf("%d",&n)!=EOF){
TreeNode *pNode=NULL;
if(n>0){
TreeNode *pNode=(TreeNode*)malloc(n*sizeof(TreeNode));
if(pNode==NULL){
exit(EXIT_FAILURE);
}
//接下来开始接受每个节点的value
int i,val;
for( i=0;i<n;i++){//这里节点下标是从0开始的
scanf("%d",&val);
pNode[i].mValue=val;
pNode[i].pLeftChild=-1;//-1表示无子节点
pNode[i].pRightChild=-1;
}
//接下来开始接受每个节点的左右节点
for( i=0;i<n;i++){
//下面的while循环是跳过缓冲区得换行符
while(getchar()!='\n'){
continue;
}
char ch;
scanf("%c",&ch);
if(ch=='d'){//此节点有左右两个节点
int leftIndex;
int rightIndex;
//scanf("%d %d",&leftIndex,&rightIndex);//leftIndex为第leftIndex个节点 ,从1开始,因此为存储在数组中,需要减 1
scanf("%d",&leftIndex);
scanf("%d",&rightIndex);
pNode[i].pLeftChild=leftIndex-1;
pNode[i].pRightChild=rightIndex-1;
}
else if(ch=='l'){
int leftIndex;
scanf("%d",&leftIndex);//leftIndex为第leftIndex个节点 ,从1开始,因此为存储在数组中,需要减 1
pNode[i].pLeftChild=leftIndex-1;
}
else if(ch=='r'){
int rightIndex;
scanf("%d",&rightIndex);
pNode[i].pRightChild=rightIndex-1;
}
else if(ch=='z'){
continue;
}
else{
// exit(EXIT_FAILURE);
}
}
//以上创建好一个二叉树
mirrorBinaryTree(pNode,0); //得到镜像二叉树
//按前序遍历将节点中的value保存在一个数组中
int * preTraversal;
preTraversal=(int *)malloc(n*sizeof(int));
if(preTraversal==NULL){
exit(EXIT_FAILURE);
}
memset(preTraversal,0,n*sizeof(int));
saveValueByPreTraversal(pNode,0,preTraversal,n);
for(int i=0;i<n;i++){
printf("%d ",preTraversal[i]);
}
free(preTraversal);
preTraversal = NULL;
free(pNode);
pNode = NULL;
}
if(n<=0){
printf("NULL\n");
continue;
}
}
return 0;
}
在调试的过程中,大概花了很长的时间才搞定,刚开始将将
mirrorBinaryTree(pNode,0); //得到镜像二叉树
放在
if(n>0){
}
模块之后,发现,永远输出的是全零的结果,经过调试发现:当我们将mirrorBinaryTree(pNode,0);
这行代码放在if(n>0){}
模块之后pNode
这个指针为NULL。解决方法就是将后面的代码放在if(n>0){}
模块之后即可。