所以我有一些遗留代码,我很乐意使用更现代的技术。但我担心,鉴于事物的设计方式,这是一个不可选择的选择。核心问题是,节点通常一次只能在一个列表中。像这样:
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解决方案,还是以最佳方式手动滚动?我有一种感觉,手动滚动的方式就是答案,但我想我会问。
答案 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 ++中重新实现该功能。一些问题可以帮助您回答这些问题,
对这些中的一些或全部的答案可能是,“没有真正的理由,这就是他们如何实现它”。如果是这样,你可以用非侵入式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_back
或push_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);
}
};