给定一个树结构,你如何使用递归使其成为一个简单的链接列表?

时间:2009-05-30 20:03:01

标签: algorithm recursion

给定一个二叉树(仅限左右子),如何编写递归函数使其成为一个简单的链接列表? (不应该创建新的数据结构。伪代码没问题)。假设每个节点都有一个整数值,如123,或2或3.最终的链接列表应包含树中的所有节点。订单并不重要。

更新:需要就地。不应该创建新的数据结构。

9 个答案:

答案 0 :(得分:3)

总是有不同的方法来迭代树,如下所示:

  • 预购
  • 后序

您可以选择其中任何一个来形成您的列表......

例如(伪代码,PreOrder):

function treeToList(LinkedList l, Tree t)
    if(t not nil)
        l.add(t.element)
        treeToList(l, t.Left)
        treeToList(l, t.Right)
    endif
end function

Remenber:如果您在二叉搜索树上执行InOrder,您将按排序顺序获取元素。

答案 1 :(得分:1)

不要粗鲁,但这听起来有点像家庭作业。让我作一个答案说明:

  • 您为结果创建一个空的链接列表。

  • 创建一个带有链表和节点的帮助功能。

  • 辅助函数应该将子节点(如果有的话)添加到列表中,并在子节点上递归调用自身(如果有的话)。

  • 将根节点添加到结果列表中。

  • 在根节点和结果列表上调用辅助函数。

  • 将结果列表返回给调用者。

维基百科上有很多相关内容:binary treestree traversal

编辑或查看Kevin发布的伪代码: - )

答案 2 :(得分:1)

由于您已将其标记为作业,我将在没有源代码或伪代码的情况下回复,但会有更全面的描述。

由于您的树将包含您想要包含在链接列表中的所有值,因此我们必须确保我们全部覆盖它们。

为此,我们必须确保处理每个叶节点。

要做到这一点,我们需要确保我们处理每个节点的每个左右孩子。

让我们从根节点开始,根节点通常是您在谈论二叉树时引用的节点。

我假设您知道如何通过顺序追加项目来生成链接列表。

因此,为了处理根节点,我们这样做:

  • 如果root包含值:将值附加到列表

它处理可以选择存储在根节点中的单个值。一些二叉树仅在叶节点(没有子节点的节点)中存储值,大多数存储值也存储在内部节点中(节点带有子节点)。

但那当然会让我们无处可去,因为我们只添加了一个项目,我们甚至不知道这个特定值在所有值中的位置,所以它可能是第一个,也可能是最后一个,或者任何在之间。

但是,我们知道如果根节点在左“方向”上有子节点,那么我们可能在所有节点中找到的任何值都将出现在根节点中的节点之前。

我们也知道,如果根节点在正确的“方向”上有子节点,那么这些值将在它之后。

所以我们能做的就是:

  • 处理左子树中的所有节点
  • 在节点
  • 中附加值
  • 处理右子树中的所有节点

这种方法假定:

  • 节点值是有序的(即,左子树位于节点本身的值之前,等等)。
  • 您希望按顺序排列值

如果您将上述方法定义为方法,您将拥有以下内容:

to process a node, do this:
    first process the left-child sub-node, if present
    then append the value of the node, if any
    then process the right-child sub-node, if present

在上面的伪代码中,您看到“process”一词,您可以将相同的过程应用于这些节点,如上所述。

这是处理简单二叉树并将结果附加到给定链表的C#代码:

public void AppendTreeToLinkedList<T>(Node<T> node, LinkedList<T> list)
{
    if (node.LeftChild != null)
        AppendTreeToLinkedList(node.LeftChild, list);
    list.Append(node.Value);
    if (node.RightChild != null)
        AppendTreeToLinkedList(node.RightChild, list);
}

答案 3 :(得分:1)

要获得以与原始树相同的方式排序的双向链表,C#代码:

function Listify(Node n, out Node First, out Node Last)
{
    if ( Node.Left != null )
    {
        Node Tmp;
        Listify(Node.Left, out First, out Tmp);
        Node.Left = Tmp;
    }
    else
    {
        First = Node;
    }
    if ( Node.Right != null )
    {
        Node Tmp;
        Listify(Node.Right, out Tmp, out Last);
        Node.Right = Tmp;
    }
    else
    {
        Last = Node;
    }
}

答案 4 :(得分:0)

你真的在问我如何走二叉树。答案可以在任何关于算法和数据结构的书中找到。

答案 5 :(得分:0)

你可以按照许多顺序“走树”,主要是前,后和有序。这是有序的伪代码,例如:

def in_walk(tree, doit):
  if tree is null: return
  in_walk(tree.left, doit)
  doit(tree.root)
  in_walk(tree.right, doit)

我希望这个伪代码中的假设是显而易见的:一个树有左右链接,可以为null,意思是“不再是在这里走路”,还有一个根节点;你可以在给定节点参数的情况下传递一个正确思考的函数或闭包(附加到链表或其他任何东西)。

答案 6 :(得分:0)

/* bst.c: sort the input numbers and print them forward and backward with no duplicates */

#include <stdio.h>
#include <stdlib.h>

struct node {
    int key;
    struct node *left;
    struct node *right;
};

static struct node **bst_find(struct node **root, int key) {
    struct node **n;

    n = root;
    while (*n != NULL && (*n)->key != key) {
        if (key < (*n)->key) {
            n = &(*n)->left;
        } else {
            n = &(*n)->right;
        }
    }
    return n;
}

static void bst_insert(struct node **root, int key) {
    struct node **n;

    n = bst_find(root, key);
    if (*n == NULL) {
        *n = malloc(sizeof (**n));
        (*n)->key = key;
        (*n)->left = NULL;
        (*n)->right = NULL;
    }
}

/* massage the tree rooted at "root" to be a doubly-linked list
 * return the leftmost and rightmost nodes via the parameters "leftend" and "rightend"
 * bst_flatten() is invoked 2N+1 times, where N is the number of tree elements
 */
static long Flatten_count = 0;
static void bst_flatten(struct node **leftend, struct node **rightend, struct node *root) {
    Flatten_count++;
    if (root != NULL) {
        /* flatten the left side of the tree */
        *leftend = root;
        bst_flatten(leftend, &root->left, root->left);
        /* if necessary, splice "root" onto the right end */
        if (root->left != NULL) {
            root->left->right = root;
        }
        /* flatten the right side of the tree */
        *rightend = root;
        bst_flatten(&root->right, rightend, root->right);
        /* if necessary, splice "root" onto the left end */
        if (root->right != NULL) {
            root->right->left = root;
        }
    }
}

int main(void) {
    int key;
    long N = 0;
    struct node *root = NULL;
    struct node *leftend = NULL;
    struct node *rightend = NULL;
    struct node *n;

    /* read the input into a bst */
    while (scanf("%d", &key) == 1) {
        N++;
        bst_insert(&root, key);
    }
    /* make a list */
    bst_flatten(&leftend, &rightend, root);
    /* traverse the list forward */
    for (n = leftend; n != NULL; n = n->right) {
        printf("%d\n", n->key);
    }
    /* traverse the list backward */
    for (n = rightend; n != NULL; n = n->left) {
        printf("%d\n", n->key);
    }
    fprintf(stderr, "%ld items input, %ld invocations of bst_flatten()\n", N, Flatten_count);
    return 0;
}

答案 7 :(得分:0)

假设树具有包含指向左右节点的指针的节点。我们最终只使用正确的节点指针列表。

listify( node )
    if node has no children 
        return

    else if node.left == null
        listify(node.right)

    else if node.right == null
        listify(node.left)
        mode.right = node.left

    else
        listify(node.left)
        listify(node.right)

        temp = node.left
        while temp.right != null
            temp = temp.right

        temp.right = node.right

        node.right = node.left

答案 8 :(得分:0)

在Scheme中,使用memoized递归,有序算法将是:

(define (tree->list tree)
  (define empty-set (list))
  (define (copy-to-list tree result-list)
    (if (null? tree)
      result-list
      (copy-to-list (left-branch tree)
                    (cons (entry tree)
                          (copy-to-list (right-branch tree)
                                        result-list)))))
   (copy-to-list tree empty-set))

这假设树结构表示为:

(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
  (list entry left right))

N.B。我本来可以使用文字'()作为empty-set,但是这会扰乱块引用代码的颜色编码。