您的位置:首页 > 其它

由反序列化二叉树实现函数引起的二叉树节点递归调用问题

2017-08-31 17:02 507 查看
          在刷剑指offer中遇到一个反序列化二叉树问题,将给定的二叉树前序遍历字符串(节点之间用“,”分割,空节点我用的“#”)。代码用递归很容易实现,由于递归中不保存int型数据,为了给字符串遍历计数,用了一个只有一个元素的数组(目前没有想到更好的方法,返回值其他值已被预订)   实现方法如下:

public class Demo {

TreeNode Deserialize(String str) {
if(str.length()<=0)
return null;
String[] strArray=str.split(",");
TreeNode pHead=new TreeNode(Integer.parseInt(strArray[0]));
int[] array1=new int [1];
array1[0]=0;
deseiriaImp(pHead,strArray,array1);
return pHead;
}

private void deseiriaImp(TreeNode node,String[] strArray, int[] array1) {
if( strArray[array1[0]].equals("#") || (array1[0]==strArray.length))
{
array1[0]++;
return ;
}
node=new TreeNode(Integer.parseInt(strArray[array1[0]]));
array1[0]++;
deseiriaImp(node.left,strArray,array1);
deseiriaImp(node.right,strArray,array1);

}

public static void main(String[] args)
{
TreeNode node1=new TreeNode(1);
TreeNode node2=new TreeNode(2);
TreeNode node3=new TreeNode(3);
TreeNode node4=new TreeNode(4);
TreeNode node5=new TreeNode(5);
TreeNode node6=new TreeNode(6);
node1.left= node2;
node1.right=node3;
node2.left= node4;
node2.right=null ;
node3.left=node5 ;
node3.right= node6;
node4.left= null;
node4.right=null;
node5.left= null;
node5.right=null;
node6.left= null;
node6.right=null ;
String seriaStr="1,2,4,#,#,#,3,5,#,#,6,#,#";
new Demo().Deserialize(seriaStr);
}
}


调试结果(调用递归函数后,pHead的值):



        但是结果却不对,返回的pHead的值为1,子树为空!我调试进递归函数发现运算程序是对的呀。我一度开始怀疑对象在调用中不是直接引用的,而是像基本类型变量一样复制的。为此,做了个实验,在实验中同样参数为一个非空的节点,但是在调用函数中给节点参数加上非空子节点,并改变节点参数的值,然后看pHead子节点有没有改变。代码如下:

public class Test {

void testNode(TreeNode node)
{
node.val=6;
node.left=new TreeNode(2);
node.right=new TreeNode(3);
}

public static void main(String[] args)
{
TreeNode node1=new TreeNode(1);
new Test().testNode(node1);
System.out.println(node1.val);
}
}


      实验结果:



     这里实验结果证明,调用函数里的对象是直接引用的,而不是复制的。反序列化二叉树的代码也没问题呀。后来不得不改变的策略:用递归函数返回头结点。代码其他地方完全没有变,只是加了返回值,然后将返回值赋给引用节点的左右节点。还是贴出完整代码(为了调试没有直接返回递归结果):

public class Solution
{
TreeNode Deserialize(String str) {
if(str.length()<=0)
return null;
String[] strArray=str.split(",");
TreeNode pHead=new TreeNode(Integer.parseInt(strArray[0]));
int[] array1=new int [1];
array1[0]=0;
TreeNode  res=deseiriaImp(pHead,strArray,array1);
return res;
}

private TreeNode deseiriaImp(TreeNode node,String[] strArray, int[] array1) {
if( strArray[array1[0]].equals("#") || (array1[0]==strArray.length))
{
array1[0]++;
return null;
}
node=new TreeNode(Integer.parseInt(strArray[array1[0]]));
array1[0]++;
node.left=deseiriaImp(node.left,strArray,array1);
node.right=deseiriaImp(node.right,strArray,array1);
return node;
}

public static void main(String[] args)
{
TreeNode node1=new TreeNode(1);
TreeNode node2=new TreeNode(2);
TreeNode node3=new TreeNode(3);
TreeNode node4=new TreeNode(4);
TreeNode node5=new TreeNode(5);
TreeNode node6=new TreeNode(6);
node1.left= node2;
node1.right=node3;
node2.left= node4;
node2.right=null ;
node3.left=node5 ;
node3.right= node6;
node4.left= null;
node4.right=null;
node5.left= null;
node5.right=null;
node6.left= null;
node6.right=null ;
String seriaStr="1,2,4,#,#,#,3,5,#,#,6,#,#";
new Solution().Deserialize(seriaStr);
}
}


     调试结果(调用递归函数后,pHead的值):



     这次结果正确了。在普通函数中直接改变pHead的引用可以,为什么在没有返回值的递归中不行呢?pHead返回的节点值是1,而不是null说明,说明程序在逻辑上是正确的,与是否递归没有关系。在递归函数中直接用deseiriaImp(node.left,strArray,array1),认为下次递归的输入变量node就和上次的node.left关联。在递归遍历树的时候的确是这样,因为树已经存在,节点的子节点已经确定。但是如果node.left等于null的时候,它们将失去关联性,在子递归函数中改变node对上一递归函数的节点没有任何影响。deseiriaImp(node.left,strArray,array1)中的node.left并没有将下次递归中的node与本次node的左子树绑定。正确的方法是:只能显性的赋值,让node.left=deseiriaImp(node.left,strArray,array1),使节点关联起来。递归函数最后将头结点返回。

     

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐