Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/155.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++ 元素如何在向量中找到自己的索引?_C++_C++11_Stl_Tree - Fatal编程技术网

C++ 元素如何在向量中找到自己的索引?

C++ 元素如何在向量中找到自己的索引?,c++,c++11,stl,tree,C++,C++11,Stl,Tree,我试图使用std::unique\u ptr重新实现一个树数据结构,其思想是父节点将拥有其子节点,这些子节点存储在unique\u ptr的向量中 出于接口的原因,我需要一种方法,其中节点会破坏自身。在这种情况下,我认为节点需要从其父节点的子向量中删除自身 下面的实现“有效”(在c++11编译器中),但它非常丑陋,我确信它是处理这个问题的次优方法 #include <iostream> #include <memory> #include <vector> #

我试图使用
std::unique\u ptr
重新实现一个树数据结构,其思想是父节点将拥有其子节点,这些子节点存储在
unique\u ptr
的向量中

出于接口的原因,我需要一种方法,其中节点会破坏自身。在这种情况下,我认为节点需要从其父节点的子向量中删除自身

下面的实现“有效”(在c++11编译器中),但它非常丑陋,我确信它是处理这个问题的次优方法

#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>

struct Node {
    typedef std::vector<std::unique_ptr<Node>> vec_node_uptr;

    unsigned        id;
    Node*           parent;
    vec_node_uptr   child_nodes;

    // ctor
    Node(unsigned id): id(id){ parent = nullptr; }

    void add_child(Node* new_child){
        new_child -> parent = this;
        child_nodes.push_back( std::unique_ptr<Node>(std::move(new_child) ) );
    }

    int where_am_i(){
        int result_ = 0;
        for(auto& i: this -> parent -> child_nodes) {
            if (this == i.get()) {
                return result_;
            } else {
                result_++;
            }
        }
    }

    void suicide(){
        parent -> child_nodes.erase(parent -> child_nodes.begin()+ where_am_i());
    }
};


int main()
{
    std::unique_ptr<Node> root(new Node(0));

    root -> add_child(new Node(1));
    root -> add_child(new Node(2));

    root -> child_nodes[0] -> add_child(new Node(3));
    root -> child_nodes[0] -> add_child(new Node(4));
    root -> child_nodes[1] -> add_child(new Node(5));
    root -> child_nodes[1] -> add_child(new Node(6));

    root -> child_nodes[1] -> suicide();

    return 0;
}
#包括
#包括
#包括
#包括
结构节点{
typedef std::vec_node_uptr向量;
无符号id;
节点*父节点;
向量节点子节点;
//执行器
节点(无符号id):id(id){parent=nullptr;}
无效添加子节点(节点*新子节点){
新建子项->父项=此项;
子节点。向后推(std::unique_ptr(std::move(new_child));
}
int where_am_i(){
int结果=0;
用于(自动&i:此->父->子节点){
if(this==i.get()){
返回结果;
}否则{
结果++;
}
}
}
无效自杀(){
父节点->子节点。擦除(父节点->子节点。开始()+何处是i());
}
};
int main()
{
std::unique_ptr root(新节点(0));
根->添加子节点(新节点(1));
根->添加子节点(新节点(2));
根->子节点[0]->添加子节点(新节点(3));
根->子节点[0]->添加子节点(新节点(4));
根->子节点[1]->添加子节点(新节点(5));
根->子节点[1]->添加子节点(新节点(6));
根->子节点[1]->自杀();
返回0;
}

有什么建议吗?可能使用
std::find

您可以使用find_if和lambda更优雅地解决这个问题:

void suicide() 
{
    auto& parentsChildren = parent->child_nodes;
    parentsChildren.erase(find_if(begin(parentsChildren), end(parentsChildren), 
                           [&](const unique_ptr<Node>& node) { return node.get() == this; }));
}
void自杀()
{
auto&parentsChildren=parent->child\u节点;
parentsChildren.erase(查找if(开始)(parentsChildren),结束(parentsChildren),
[&](const unique_ptr&node){return node.get()==this;});
}

如果您希望在当前数据结构中有一个恒定的时间
where_am_i()
,则需要在节点本身中存储索引或迭代器。这是(a)重复的,(b)将带来进一步的复杂性,因为无论何时删除不是其父节点最后一个子节点的节点,都需要更新所有后续子节点的索引/迭代器

再次强调,如果从向量中删除一个元素,除非您总是从末尾(或接近末尾)删除,否则使用恒定时间
,这可能没有真正的好处,因为从向量中删除一个元素无论如何都是O(n)

但是,如果您通常从末尾删除,并且如果不需要将一组子节点的所有权从父节点转移出去,那么这里有一个替代的、更简单的设计,它可以避免在每个节点中存储索引或迭代器:

C++标准保证<>代码STD::vector s,像数组一样,将它们的内容在内存中连续地排列。因此,如果

子节点
向量实际上按值存储了它的元素,也就是说,如果它被声明为

typedef std::vector<Node> vec_node_uptr;
vec_node_uptr child_nodes;

我想这个问题更适合我,因为我会把责任推给父母。孩子们会调用parent->remove_child(this)@Enigma:OK,但找到孩子的基本问题保持不变。所有这些变化都是源代码的位置:-在这种情况下,父代不是其子代的唯一所有者,因为子代可以确定自己的生命周期何时结束。我怀疑这就是为什么您的解决方案看起来很笨拙的原因,因为
unique\u ptr
是为指针对相关对象拥有唯一所有权的情况而设计的。实际上,您的设计使父级具有唯一的指向子级的“弱”指针,子级的生命周期是自我管理的。一种方法可能是实现
unique\u-weak\u-ptr
unique\u-strong\u-ptr
self\u-ownership
CRTP类。。。即使这样,指向child的指针也会失效,但计数不会失效。@Yakk:是这样吗?我觉得父母仍然拥有自己的孩子们的记忆,也就是说,当父母被删除时,孩子们会被自动销毁“自杀”只是一个方便的函数,可以有效地调用父方法。如果我错了,请纠正我。从末尾删除是不相关的。如果树有父链接,则已覆盖到其他父节点的传输。(如果没有,那么已经编写了算法来避免这个问题。)没有理由以任何其他方式实现
where\u am\u i
。@j\u random\u hacker:真是个有趣的主意。我希望使用do way在节点之间进行更多的所有权转移,而不是删除。@Potatoswatter:既然你不是OP,你说从末尾删除与什么权限无关?有些算法可以设计为只从末尾删除,而其他算法则不能,因此总体时间复杂度将取决于OP算法所属的类别。你知道OP打算使用哪些算法吗?@j_random_hacker,因为它与解决方案是否有效无关<代码>此-&parent->children[0]
是解决方案,句号。你说“如果……和……那么解决方案是减法”,但它们是错误的条件。@Potatoswatter:我的意思是,如果你总是从(接近)结尾处删除,我建议的解决方案只会给你带来一些好处。如果您不打算从(接近)结尾处删除,那么我的O(1)解决方案将没有实际用途,因为您将立即执行O(n)删除步骤。这真的很不清楚吗?这很合适。我还没看过lambda expr。对性能有什么评论吗?std::find_if将在parentsChildren上执行线性搜索,因此复杂性不像j_random_hacker的答案那样恒定(它是
size_t where_am_i() {
    return this - &parent->child_nodes[0];
}