【问题标题】:How to tree traversal a multiway tree如何树遍历多路树
【发布时间】:2019-04-11 14:50:46
【问题描述】:

我试图遍历多路树,但我试图以一种有效的方式进行,但这并没有真正帮助我,更重要的是我想递归地进行。

我的想法是这样的:我有一棵树、一个孩子和它的兄弟姐妹。我想递归地和孩子们一起下去,然后只要它有兄弟姐妹也递归地去他们身上。

在这里,我将向您介绍我的数据结构以及我如何尝试实现它。这是一个完整的功能“可测试”,它还将创建一张照片供您查看树并使用代码:

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

#define SIZE    100

typedef struct tree {
    int value;
    struct tree *child, *sibling;
} *Tree;

Tree initTree(int value) {
    Tree root = malloc(sizeof(struct tree));
    root->value = value;
    root->child = NULL;
    root->sibling = NULL;
    return root;
}

void drawTreeHelper(Tree tree, FILE* stream) {
    Tree tmp;
    if (tree == NULL) {
        return;
    }
    fprintf(stream, "    %ld[label=\"%d\", fillcolor=red]\n", (intptr_t) tree, tree->value);
    tmp = tree->child;

    while (tmp != NULL) {
        fprintf(stream, "    %ld -> %ld \n", (intptr_t) tree, (intptr_t) tmp);
        drawTreeHelper(tmp, stream);
        tmp = tmp->sibling;
    }
}

void drawTree(Tree tree, char *fileName) {
    FILE* stream = fopen("test.dot", "w");
    char buffer[SIZE];
    fprintf(stream, "digraph tree {\n");
    fprintf(stream, "    node [fontname=\"Arial\", shape=circle, style=filled, fillcolor=yellow];\n");
    if (tree == NULL)
        fprintf(stream, "\n");
    else if (!tree->child)
        fprintf(stream, "    %ld [label=\"%d\"];\n", (intptr_t) tree, tree->value);
    else
        drawTreeHelper(tree, stream);
    fprintf(stream, "}\n");
    fclose(stream);
    sprintf(buffer, "dot test.dot | neato -n -Tpng -o %s", fileName);
    system(buffer);
}

int main() {
    int i;
    char buffer[SIZE];
    Tree *forest = malloc(5 * sizeof(Tree));
    for (i = 0; i < 5; i++) {
        forest[i] = initTree(i);
    }

    forest[4]->child = forest[3];
    forest[4]->child->sibling = forest[2];
    forest[1]->child = forest[0];
    forest[1]->child->sibling = forest[4];

    for (i = 0; i < 5; i++) {
        sprintf(buffer, "tree_%d.png", i);
        if (forest[i]) {
            drawTree(forest[i], buffer);
        }
    }
    return 0;
}

我要创建的功能保持不变,即:

Tree findChild(Tree root, int value)
{
    if(!root) return NULL;
    if(root->value == value) return root;

    return findChild(root->child, value);
    Trie iter = root;
    while(iter)
    {
        return findChild(iter->sibling, value);
        iter = iter->sibling;
    }
}

我希望找到子节点,但如果节点不是根的直接子节点,它会返回 NULL。 我要创建的函数的期望:在树中以最有效的方式找到孩子。

【问题讨论】:

  • sibling 是树的兄弟,还是 child 的兄弟?我不明白这种结构与“经典”树有何不同。
  • @EugeneSh。是树的兄弟,当前的“查看”节点,与“经典”树没有什么不同,只是符号不同。
  • @Yunnosch 为什么这不是一个最小的、完整的和可验证的例子?我也会添加一张有树的照片,但我的名声太小,无法这样做。
  • 无法编译运行。它没有证明你的问题。它缺少声明。对于所有这些来说,它太小了,但它不是最小的,因为最小的含义“足够大”。我怀疑您是否阅读了我提供的链接并认为“是的,所有这些都适用于我展示的代码。”

标签: c tree tree-traversal multiway-tree


【解决方案1】:

这是你的功能:

Tree findChild(Tree root, int value)
{
    if(!root) return NULL;
    if(root->value == value) return root;

在这里,您遍历子节点,但您说的是return

    return findChild(root->child, value);

所以这段代码永远不会被执行:

    Tree iter = root;
    while(iter)
    {
        return findChild(iter->sibling, value);
        iter = iter->sibling;
    }
}

此外,迭代是无用的,因为无论如何你都会通过调用findChild 遍历下一个兄弟。所以函数应该是这样的:

Tree findChild(Tree root, int value)
{
    if(!root) return NULL;
    if(root->value == value) return root;

    Tree *ret = findChild(root->child, value);
    if (!ret)
        ret = findChild(root->sibling, value);

    return ret;
}

这应该可以如您所愿。

编辑:

在(无条件的)return 之后,永远不会执行代码。根本没有代码路径可以“绕过”返回。

如果树中的项目不遵循特定顺序,这可能是最有效的方式(就运行时复杂性而言)。如果树是有序的,您可以通过查看当前项目,将其与搜索到的项目进行比较,然后 - 基于比较结果 - 仅选择两个路径之一 childsibling 而不是遍历两者都有。

【讨论】:

  • 您好!谢谢你的回答,但为什么后面的代码永远不会执行?这不是递归的工作原理吗?另外,这是最高效的搜索方式吗?
  • @A.Cretan 我编辑了答案以解决您的问题
  • 什么是“无条件退货”?复杂度也会是 O(N)?
  • @A.Cretan 无条件返回是一种返回,它不在条件块内(即不在 if/else 块内)。是的,这里的运行时复杂度是 O(n)(最坏和平均情况),其中 n 是树中元素的数量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多