【问题标题】:C++ Reorganizing an array to fill in the gaps?C ++重组数组以填补空白?
【发布时间】:2011-03-07 19:59:08
【问题描述】:

我不确定 Reorganizing 这个词是否正确,但这是我可以描述我正在寻找的东西的唯一方式。

如果我有一组猫,就像这样:

CAT *myCats[99];

myCats[0] = new CAT;
myCats[1] = new CAT;
myCats[2] = new CAT;
myCats[3] = new CAT;
myCats[4] = new CAT;
myCats[5] = new CAT;

在某个时间点,假设 myCats[3] 被删除:

delete myCats[3];

现在我有以下内容:

myCats[0]
myCats[1]
myCats[2]
myCats[4]
myCats[5]

有没有一种简单的方法来重新组织数组,使其移动 4->3 和 5->4,基本上填补空白?

myCats[0]
myCats[1]
myCats[2]
myCats[3]
myCats[4]

是实现这一点的最佳方法,本质上是遍历数组并确定一个元素是否为空/缺失,我只需要将下一个现有元素移动到它的位置吗?我该怎么做?如何确定数组中任何点的 Cat 元素是否存在?或者有没有更简单的预先确定的方法来完成我需要的?

对不起,如果示例和语法有点不对劲。我是 C++ 新手。

更新

感谢您的快速建议。看起来向量是要走的路。我总是忘记向量。在我的脑海中,Vector 只是一个包含 x、y 和 z 值的容器 :-)

【问题讨论】:

  • 是的,不幸的是,数组在 C++ 中以其自然语法高度可见,而通常更好的向量却不是。我还认为,如果智能指针在某种程度上是 C++ 中的“默认”指针类型,那么世界将会变得更美好,raw_pointer<T> 是关注性能的专家的固定扩展。

标签: c++ arrays


【解决方案1】:

如果您使用 C++,则可以使用 std::vector 更轻松地完成此操作:

std::vector<CAT*> cats;
cats.push_back(new CAT);
cats.push_back(new CAT);
cats.push_back(new CAT);

// remove the second cat
delete cats[1];
cats.erase(cats.begin() + 1);

现在向量中有两只猫(插入的第一只和第三只猫),它们的索引分别为 0 和 1。

但是,在 C++ 中,没有理由动态分配所有内容,因此您可能只使用 vector&lt;CAT&gt; 会更好:

std::vector<CAT> cats;
cats.push_back(CAT());
cats.push_back(CAT());
cats.push_back(CAT());

// remove the second cat
cats.erase(cats.begin() + 1);

这样,猫的销毁会自动处理,您不必担心自己管理任何内存。

如果您确实必须使用指针(例如,您的类是多态基类),您可能希望使用智能指针的std::vector(例如,shared_ptrs )。使用智能指针,您不必记住在使用完对象后删除它们——它会自动完成。例如,上面使用shared_ptr 的代码如下所示:

std::vector<std::shared_ptr<CAT> > cats;
cats.push_back(std::make_shared(new CAT));
cats.push_back(std::make_shared(new CAT));
cats.push_back(std::make_shared(new CAT));

// remove the second cat
// note we don't need to call delete; shared_ptr does that for us
cats.erase(cats.begin() + 1);

(您的标准库可能尚未在 std 命名空间中包含 shared_ptr;在这种情况下,you may find it elsewhere)。如果你不熟悉shared_ptrthe Boost documentation 是一个很好的介绍。

【讨论】:

  • 是的,vector&lt;CAT*&gt;CAT * 的数组要好,但是由于 OP 是 C++ 的新手,我怀疑 vector&lt;CAT&gt; 会涵盖他的用例并且会更好(更安全 + 更容易)再次。
  • @j_random_hacker:哦;那是个很好的观点。我不应该在喝咖啡之前发布答案。我使用vector&lt;CAT&gt; 添加了一个示例。非常感谢。
【解决方案2】:

正如其他人指出的那样,使用 std::vector 将为您完成所有重新分配,但它仍然是一个 O(n) 操作。但是,您可以使用另一种数据结构做得更好。例如std::list 将允许您从 O(1) 列表中的任何位置删除一个元素。

最终哪种数据结构最合适将取决于您需要支持的所有操作、它们的相对频率以及每个操作所需的性能。

【讨论】:

  • vector 的每个单独删除都是 O(n) 的优点。如果您可以通过单独查看一个元素来决定是否应该删除它,那么一种方法是使用单个 remove_if() 在单个 O(n) 遍中执行所有删除。 (与直觉相反,这需要随后调用erase()。)
  • 是的 remove_if ,但是 OP 正在使用该容器可能会使 vector 成为正确的选择,但我们只能看到他们想从中间删除元素,因此很难客观地推荐一个容器超过另一个
【解决方案3】:

您可以在删除后将 NULL 分配给指针,然后检查指针是否为 NULL 或保留一个大小相同的 bool 数组,以指示该对象是否存在。至于重组:如果顺序确实很重要,那么您必须按照描述移动所有元素。如果顺序无关紧要,只需将最后一个元素移动到缺失的间隙中即可。

【讨论】:

    【解决方案4】:

    有什么特殊原因不能使用std::vector 代替数组吗? Vector 会自动调整大小,因此您不必担心这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-19
      • 2022-11-16
      • 1970-01-01
      • 2019-09-30
      • 2020-07-06
      • 2018-10-28
      • 1970-01-01
      相关资源
      最近更新 更多