Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/150.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C+中,有没有一种好方法可以打印出类似JSON的trie结构(仅限迭代解决方案)的扁平名称空间+;11? 我试图在C++中创建一个TIE结构,其中每个节点都保存一个名称和一些数据,并且可以保存对任意数目的子节点的引用。p>_C++_C++11_Dictionary_Traversal_Trie - Fatal编程技术网

在C+中,有没有一种好方法可以打印出类似JSON的trie结构(仅限迭代解决方案)的扁平名称空间+;11? 我试图在C++中创建一个TIE结构,其中每个节点都保存一个名称和一些数据,并且可以保存对任意数目的子节点的引用。p>

在C+中,有没有一种好方法可以打印出类似JSON的trie结构(仅限迭代解决方案)的扁平名称空间+;11? 我试图在C++中创建一个TIE结构,其中每个节点都保存一个名称和一些数据,并且可以保存对任意数目的子节点的引用。p>,c++,c++11,dictionary,traversal,trie,C++,C++11,Dictionary,Traversal,Trie,我希望遍历trie,以便以迭代的方式打印到给定节点的“平坦”路径 给定一棵树,其中节点由以下各项定义: class Node { public: virtual std::string node_name() = 0; }; class TreeNode : Node { public: std::string name; std::map<std::stri

我希望遍历trie,以便以迭代的方式打印到给定节点的“平坦”路径

给定一棵树,其中节点由以下各项定义:

    class Node
    {
            public:
            virtual std::string node_name() = 0;
    };


    class TreeNode : Node
    {
    public:
        std::string name;
        std::map<std::string, TreeNode&> children {};


        TreeNode(const std::string&name) : name(name) {}


        std::string node_name()
        {
            return name;
        }

        void add_child(TreeNode& node)
        {
                children.insert(std::pair<std::string, TreeNode&> 
                (node.node_name(), node));
        }

    };
输出应该是(不关心顺序):

我已经实现了递归解决方案(见下文),但我想知道是否有一种迭代实现的方法(因为我希望在应用程序中尽可能避免递归)

以下是递归版本:

    void flatten_helper(TreeNode& root, 
                        const std::string& prefix)
    {
        static const std::string delimeter { "." };

        std::string namespace_path(prefix);
        if (!prefix.empty())
        {
            namespace_path.append(delimeter);
        }

        namespace_path.append(root.node_name());

        for (auto& node : root.children)
        {
            flatten_helper(node.second, namespace_path);
        }
        // do something with node/complete namespace name
        std::cout << namespace_path << std::endl;


    }

    void flatten(TreeNode& node)
    {
        std::string empty {""};

        return flatten_helper(node, empty);
    }



    int main(int argc, char** argv)
    {
        TreeNode root { "root" };

        TreeNode a { "a" };
        TreeNode b { "b" };

        TreeNode c { "c" };
        TreeNode d { "d" };
        TreeNode e { "e" };


        a.add_child(c);
        a.add_child(d);

        b.add_child(e);

        root.add_child(a);
        root.add_child(b);

        flatten(root);

        return 0;
    }

void flatten\u助手(TreeNode和root、,
常量std::字符串和前缀)
{
静态常量std::字符串delimeter{“.”};
字符串名称空间路径(前缀);
如果(!prefix.empty())
{
名称空间_path.append(delimeter);
}
名称空间_path.append(root.node_name());
用于(自动节点:root.children(&N)
{
展平辅助对象(node.second,名称空间路径);
}
//对节点/完整命名空间名称执行某些操作

std::cout将递归过程转换为交互过程的诀窍是使“挂起的工作”显式化。在您的例子中,工作单元是
TreeNode
和前缀,工作单元保存在
std::stack
中(因为递归解决方案是深度优先的)。任何(以前)递归调用必须向堆栈添加工作,当没有更多工作可用时,工作停止

void flatten_iter(TreeNode& root_node)
{
    using WorkItem = std::pair<TreeNode&, std::string>;
    static const std::string delimeter{ "." };

    std::stack<WorkItem> workitems;
    workitems.emplace(root_node, "");

    while (!workitems.empty()) {
        auto [ node, prefix ] = workitems.top();
        workitems.pop();

        std::string namespace_path(prefix);
        if (!prefix.empty())
        {
            namespace_path.append(delimeter);
        }

        namespace_path.append(node.node_name());

        for (auto& child : node.children)
        {
            workitems.emplace(child.second, namespace_path);
        }

        // do something with node/complete namespace name
        std::cout << namespace_path << std::endl;
    }
}
void flatten\u iter(树节点和根节点)
{
使用WorkItem=std::pair;
静态常量std::字符串delimeter{“.”};
std::堆栈工作项;
workitems.emplace(根节点“”);
而(!workitems.empty()){
auto[node,prefix]=workitems.top();
workitems.pop();
字符串名称空间路径(前缀);
如果(!prefix.empty())
{
名称空间_path.append(delimeter);
}
名称空间_path.append(node.node_name());
用于(自动和子节点:node.children)
{
workitems.emplace(child.second,名称空间_路径);
}
//对节点/完整命名空间名称执行某些操作

避免使用堆栈的一种方法是在树中有父指针

您的迭代器可以向下追踪树,处理底部分支中的所有对等节点,然后使用最后一个节点中的父指针返回1级,移动到该级的下一个对等节点,然后再次向下。最后,这是一个相对最小的算法


当然,对于大型树,每个节点上的父指针的成本比显式堆栈的成本高/多/多,但如果父指针还有其他用途,则值得考虑。

这种
堆栈
表示法也适用于简单的预排序迭代器:
开始
只是根节点,
运算符++
弹出顶部节点并添加子节点,
end
是空堆栈。建议您尝试将其作为练习。非常感谢您的解释和练习(我将在下一步尝试)。我有一半的解决方案(使用堆栈w/深度优先迭代),但否定将前缀作为“工作项”应用
    void flatten_helper(TreeNode& root, 
                        const std::string& prefix)
    {
        static const std::string delimeter { "." };

        std::string namespace_path(prefix);
        if (!prefix.empty())
        {
            namespace_path.append(delimeter);
        }

        namespace_path.append(root.node_name());

        for (auto& node : root.children)
        {
            flatten_helper(node.second, namespace_path);
        }
        // do something with node/complete namespace name
        std::cout << namespace_path << std::endl;


    }

    void flatten(TreeNode& node)
    {
        std::string empty {""};

        return flatten_helper(node, empty);
    }



    int main(int argc, char** argv)
    {
        TreeNode root { "root" };

        TreeNode a { "a" };
        TreeNode b { "b" };

        TreeNode c { "c" };
        TreeNode d { "d" };
        TreeNode e { "e" };


        a.add_child(c);
        a.add_child(d);

        b.add_child(e);

        root.add_child(a);
        root.add_child(b);

        flatten(root);

        return 0;
    }

void flatten_iter(TreeNode& root_node)
{
    using WorkItem = std::pair<TreeNode&, std::string>;
    static const std::string delimeter{ "." };

    std::stack<WorkItem> workitems;
    workitems.emplace(root_node, "");

    while (!workitems.empty()) {
        auto [ node, prefix ] = workitems.top();
        workitems.pop();

        std::string namespace_path(prefix);
        if (!prefix.empty())
        {
            namespace_path.append(delimeter);
        }

        namespace_path.append(node.node_name());

        for (auto& child : node.children)
        {
            workitems.emplace(child.second, namespace_path);
        }

        // do something with node/complete namespace name
        std::cout << namespace_path << std::endl;
    }
}