多个列表中的项目

时间:2010-06-16 19:53:20

标签: c++ data-structures linked-list

所以我有一些遗留代码,我很乐意使用更现代的技术。但我担心,鉴于事物的设计方式,这是一个不可选择的选择。核心问题是,节点通常一次只能在一个列表中。像这样:

struct T {
    T *next_1;
    T *prev_1;
    T *next_2;
    T *prev_2;
    int value;
};

这允许核心有一个T类型的对象被分配并插入到2个双向链表中,既美观又高效。

显然我可以只有2个std::list<T*>并且只是将对象插入两个......但是有一件事情会降低效率......删除。

代码通常需要“销毁”T类型的对象,这包括从所有列表中删除元素。这很好,因为给定T*代码可以从它存在的所有列表中删除该对象。像std::list之类的东西,我需要搜索对象以获取迭代器,然后删除它(我不能只是传递一个迭代器,因为它在几个列表中。)

对此有一个很好的c ++ - ish解决方案,还是以最佳方式手动滚动?我有一种感觉,手动滚动的方式就是答案,但我想我会问。

7 个答案:

答案 0 :(得分:3)

作为另一种可能的解决方案,请查看Boost Intrusive,其中an alternate list class有许多属性可能会对您的问题有所帮助。

在这种情况下,我认为它看起来像这样:

using namespace boost::intrusive;

struct tag1; struct tag2;

typedef list_base_hook< tag<tag1> > base1;
typedef list_base_hook< tag<tag2> > base2;

class T: public base1, public base2
{
    int value;
}

list<T, base_hook<base1> > list1;
list<T, base_hook<base2> > list2;

// constant time to get iterator of a T item:
where_in_list1 = list1.iterator_to(item);
where_in_list2 = list2.iterator_to(item);

// once you have iterators, you can remove in contant time, etc, etc.

答案 1 :(得分:2)

您可以使用std :: list,而不是管理自己的下一个/上一个指针。要解决删除问题的性能,可以将迭代器存储到对象本身(每个std :: list的一个成员可以存储该元素。)

您可以扩展它以在类中存储迭代器的向量或数组(如果您不知道元素存储的列表数量)。

答案 2 :(得分:1)

我认为正确的答案取决于此应用程序的性能关键程度。它是否在内部循环中可能会使程序花费用户可感知的运行时差异?

有一种方法可以通过创建从某些STL容器派生的自己的类来创建这种功能,但它甚至可能不值得。听起来很烦人的风险,我认为这可能是过早优化的一个例子。

答案 3 :(得分:1)

要回答的问题是为什么这个C结构首先存在。在了解该功能之前,您无法在C ++中重新实现该功能。一些问题可以帮助您回答这些问题,

  1. 为什么列出?数据是否需要序列,即按顺序排列?订单意味着什么吗?该应用程序是否需要有序遍历?
  2. 为什么两个容器?容器中的成员资格是否表明元素的某种属性?
  3. 为什么链接列表具体? O(1)插入和删除是否重要?反向迭代很重要吗?
  4. 对这些中的一些或全部的答案可能是,“没有真正的理由,这就是他们如何实现它”。如果是这样,你可以用非侵入式C ++容器解决方案替换那个侵入式C指针混乱,可能包含shared_ptrs而不是ptrs。

    我得到的是,你可能不需要重新实现任何东西。您可以放弃整个业务,并将值存储在适当的C ++容器中。

答案 4 :(得分:1)

这是怎么回事?

struct T {
    std::list<T*>::iterator entry1, entry2;
    int value;
};
std::list<T*> list1, list2;

 // init a T* item:
 item = new T;
 item->entry1 = list1.end();
 item->entry2 = list2.end();

 // add a T* item to list 1:
 item->entry1 = list1.insert(<where>, item);

 // remove a T* item from list1
 if (item->entry1 != list1.end()) {
      list1.remove(item->entry1); // this is O(1)
      item->entry1 = list1.end();
 }

 // code for list2 management is similar

你可以使T成为一个类,并使用构造函数和成员函数来完成大部分工作。如果您有可变数量的列表,则可以使用迭代器列表std::vector<std::list<T>::iterator>来跟踪项目在每个列表中的位置。

请注意,如果您使用push_backpush_front添加到列表中,则需要分别执行item->entry1 = list1.end(); item->entry1--;item->entry1 = list1.begin();以获取指向正确位置的迭代器

答案 5 :(得分:0)

听起来你正在谈论可以通过应用图论来解决的问题。因此,Boost图库可能会提供一些解决方案。

答案 6 :(得分:-1)

list::remove就是你所追求的。它将删除列表中的所有对象,其值与传入的对象相同。

所以:

list<T> listOne, listTwo;
// Things get added to the lists.
T thingToRemove;
listOne.remove(thingToRemove);
listTwo.remove(thingToRemove);

我还建议将列表节点转换为类;这样C ++会为你处理内存。

class MyThing {
  public:
  int value;
  // Any other values associated with T
};

list<MyClass> listOne, listTwo; // can add and remove MyClass objects w/o worrying about destroying anything.

您甚至可以将两个列表封装到它们自己的类中,并为它们添加/删除方法。然后,只需要在删除对象时调用一个方法。

class TwoLists {
  private:
  list<MyClass> listOne, listTwo;

  // ...

  public:
  void remove(const MyClass& thing) {
    listOne.remove(thing);
    listTwo.remove(thing);
  }
};