【发布时间】:2018-04-07 22:56:51
【问题描述】:
来自 C 背景,我正在尝试自学 C++。我一直在尝试实现 UnionFind 数据结构。我有一堂课如下:-
class UnionFind
{
private:
int count;
UnionFind* parent;
int val;
public:
UnionFind(int _val) : count(1), parent(this), val(_val) {
printf("UnionFind(): parent=%p this=%p\n", parent, this);
}
~UnionFind() {
printf("~UnionFind()\n");
}
int getcount()
{
if (parent == this)
return count;
return Find()->count;
}
int getval() { return val; }
void setparent(UnionFind* _parent) { parent = _parent; }
void setcount(int _count) { count = _count; }
// Does a union of 2 sets
void Union(UnionFind* u)
{
printf("Union(%d: this=%p, %d: u=%p)\n", val, this, u->getval(), u);
UnionFind* this_parent = Find();
UnionFind* u_parent = u->Find();
printf("this_parent=%p u_parent=%p\n", this_parent, u_parent);
if (this_parent == u_parent)
return;
if (this_parent->getcount() > u_parent->getcount()) {
this_parent->setcount(this_parent->getcount() + u_parent->getcount());
u_parent->setparent(this_parent);
} else {
u_parent->setcount(this_parent->getcount() + u_parent->getcount());
this_parent->setparent(u_parent);
}
}
// Returns the parent
UnionFind* Find()
{
//printf("%d: Find(%p) = ", val, this);
UnionFind* temp = parent;
while (temp != temp->parent)
temp = temp->parent;
//printf("%p\n", temp);
return temp;
}
};
稍后我尝试用UnionFind 的一些实例填充向量,如下所示:-
vector<UnionFind> vecs;
for (int i = 0; i < N; i++)
vecs.push_back(UnionFind(i));
运行此代码显示 UnionFind 对象都具有相同的地址。我怀疑(并确认)这是因为在循环的每次迭代中都会调用 UnionFind 的析构函数。
我的问题是:-
- 我意识到我可以创建一个指向 UnionFind 对象的指针向量作为
vector<UnionFind*>来解决这个问题,但这真的是要走的路吗?我读到与 C 不同的是,在 C++ 中可能解决很多问题,而无需求助于 new/malloc 或 delete/free。解决这个问题的 C++ 方法是什么?
[编辑]
已纠正错字。
[编辑 2]
我正在尝试实现一个不相交集/联合查找数据结构。 "parent" 最初会指向自身,但随着联合的发生,父级可能会指向不同的对象。
[编辑 3]
已添加完整代码。
【问题讨论】:
-
Vector 对其内容进行了大量的移动和洗牌。这意味着您放入其中的任何内容都必须可以安全地复制和分配。这不是因为
parent会搞砸。查看Rules of Three Five, and Zero。如果不掌握这些规则,你就不能做重要的 C++。您还需要密切关注Iterator invalidation rules,否则将指向容器中的项目的指针存储在容器中只会造成痛苦。 -
由于所有的洗牌和调整大小,正在发生很多破坏。但在
vector的内部存储调整大小之前,vecs[0]的地址将始终相同,无论UnionFind当前占用该插槽是什么。 -
感谢您提供的链接和信息,您能否说明是否有办法在不使用新/删除的情况下解决此问题?
-
您到底想解决什么问题?您是否要确保每个对象都有
parent == this? -
你需要多少
parent?使用parent,如果您允许复制或移动对象,您就有大量的簿记工作。你最好使用指针,这样地址就不会改变,但是guard the pointer with astd::unique_ptr(vector<unique_ptr<UnionFind>>) 所以它的所有权被锁定并保证删除。