如何返回双向链表并删除树的​​叶子?

时间:2015-12-11 23:19:31

标签: java algorithm list recursion

我正在开展类似SPOJ的任务。目标是在二叉树中找到叶子(不一定是BST),从树中删除它们并将它们作为一种双向链表返回,使用相同的结构 - TreeNode并且没有其他导入。例如,如果从树中删除节点2,4和3,则函数返回列表的第一个非空元素:null< - 2< - > 4 - < - > 3 - >空值。 TreeNode有一个值以及左右指针。

我使用了递归并使叶子无效以从树中删除它们并在列表中重新创建它们。为了有效地将元素添加到列表的末尾,我将指针指向列表的最后一个元素。这产生了一个众所周知的改变传递给函数的对象的问题。这是我的代码:

public TreeNode getLeaves(TreeNode root)
{
    if(root == null)
        return null;

    TreeNode start = new TreeNode(Integer.MIN_VALUE);
    TreeNode[] end = {start};
    getLeaves(root, start, end);
    return start;
}

private void getLeaves(TreeNode root, TreeNode start, TreeNode[] end)
{
    if(root == null)
        return;

    if(root.left == null && root.right == null)
    {
        addToList(root, start, end);
        root = null;
        return;
    }
    getLeaves(root.left, start, end);
    getLeaves(root.right, start, end);
}

private void addToList(TreeNode element, TreeNode start, TreeNode[] end)
{
    if(end[0].value != Integer.MIN_VALUE)
    {
        TreeNode t = new TreeNode (element.value);
        end[0].right = t;
        t.left = end[0];
        end[0] = t;
    }
    else
    {
        start.value = element.value;
    }
}

从树中删除叶子不起作用,但正确返回列表。但是,设置" start"的值TreeNode到最小的int值而不是使用null引用错误我,使用数组也是如此。使用原子参考会使它更混乱恕我直言。我非常确定有一种方法可以更优雅的方式(以及正确删除叶子),可能通过改变分配开始和结束TreeNodes的方法。我觉得我的方法和/或理解它的运作方式有问题。你能帮我把它变成一个整齐的代码并解释我的坏事吗?

2 个答案:

答案 0 :(得分:0)

您的第二个GetLeaves功能出错。语句root = null;局部变量 root的值设置为null,但其父级将保留对叶子的引用。

如果您将方法bool isLeaf()添加到TreeNode,您将会更加轻松。我将你的代码修改为我认为可行的代码。

private bool isLeaf()
{
    // This method should be in TreeNode
    return left == null && right == null;
}
// Also, TreeNode should have an Add(TreeNode) method

public TreeNode getLeaves(TreeNode root)
{
    if( root == null )  // check if the whole tree is empty
        return null;  // return something relevant here
    else if( root.isLeaf() )
        return root;  //cannot remove this leaf, unfortunately
    TreeNode leaves = new TreeNode()
    getLeaves(root, leaves);
    return leaves;
}
private void getLeaves(TreeNode current, TreeNode leaves)
{
    // current is guaranteed to be non-null and not a leaf itself.
    if( current.left.isLeaf() ) {
        leaves.add(current.left);
        current.left = null;
    } else {
        getLeaves(current.left, leaves);
    }
    if( current.right.isLeaf() ) {
        leaves.add(current.right);
        current.right = null;
    } else {
        getLeaves(current.right, leaves);
    }
}

答案 1 :(得分:0)

大卫,你100%正确。谢谢你的帮忙。如果有人想知道,这是我迄今为止制作的最优雅的解决方案,包括David的改进。我唯一不确定的是,addToList方法应该是静态的,还是在元素的上下文中调用它更为正确/通用。

public TreeNode getLeaves(TreeNode root)
{
    if(root == null)
        return null;

    if(root.isLeaf())
        return root;

    TreeNode[] listEdges = {null, null};
    getLeaves(root, listEdges);
    return listEdges[0];
}

private void getLeaves(TreeNode root, TreeNode[] edges)
{
    if(root == null)
        return;

    if(root.left != null && root.left.isLeaf())
    {
        addToList(edges, root.left);
        root.left = null;
    }

    if(root.right != null && root.right.isLeaf())
    {
        addToList(edges, root.right);
        root.right = null;
    }
    getLeaves(root.left, edges);
    getLeaves(root.right, edges);
}

private static void addToList(TreeNode[] edges, TreeNode element)
{
    if(edges[1] != null)
    {
        edges[1].right = element;
        element.left = edges[1];
        edges[1] = element;
    }
    else
    {
        edges[0] = element;
        edges[1] = edges[0];
    }
}

public boolean isLeaf()
{
    return this.right == null && this.left == null;
}