我无法在网上找到太多关于它们的信息。它们是什么以及它们通常何时使用?
感谢。
答案 0 :(得分:35)
侵入式列表是指向下一个列表节点的指针存储在与节点数据相同的结构中的列表。这通常是一个坏事,因为它将数据绑定到特定的列表实现。大多数类库(例如,C ++标准库)使用非侵入式列表,其中数据对列表(或其他容器)实现一无所知。
答案 1 :(得分:31)
我实际上喜欢侵入式模型
侵入是好的 你只需要知道你在做什么(任何容器都是如此)
答案 2 :(得分:7)
Here is a brief description that is valid for lists as well:
Object to be stored contains additional information to allow integration in container. Example:
struct Node { Node* next; // additional Node* prev; // information T data; }1. Pros:
- stores the objects themselves.
- doesn't involve memory management.
- iteration is faster.
- better exception guarantees.
- predictability in insertion and deletion of objects. (no additional (non-predictable) memory management is required.)
- better memory locality.
2. Cons:
- contains additional data for container integration. (every store type must be adapted (modified) to the container requirements.)
- caution with possible side effects when changing the contents of the stored object.(especially for associative containers.)
- lifetime management of the inserted object, independently from the container.
- object can be possibly disposed before erased from the container leading to iterator invalidation.
- intrusive containers are NON-copyable and NON-assignable.
Object doesn't "know" and contain details about the container in which is to be stored. Example:
struct Node { T data; }1. Pros:
- does not containe additional information regarding the container integration.
- object's lifetime managed by the container. (less complex.)
2. Cons:
- store copies of values passed by the user. (inplace construction possible.)
- an object can belong only to one container. (or the contaier should store pointers to objects.)
- overhead on storing copies. (bookkeeping on each allocation.)
non-copyable or non-movable objects CAN'T be stored in non-intrusive containers.- can't store derived object and still maintain its original type. (slicing - looses polymorphism.)
答案 3 :(得分:4)
Intrusives列表是对象本身是列表或列表单元格的列表。根据具体情况,它们是好事或坏事。
在一些已定义的模块(不可协调的一组类一起工作)中,它可能是将类之间的关系联系起来的最佳方法。它们允许免费直接和全面管理普通关系,例如unicity(例如:苹果在appletrees中不会出现两次,而且这不需要任何关键,而苹果不属于两个不同的树),它们是可导航的在两个方向上(直接给appletree给苹果和苹果给予一些appletree)。所有基本操作都是O(1)(在某些外部容器中没有搜索)。
两个模块之间的侵入列表非常糟糕。因为它们将捆绑在一起,而模块的合理性是代码独立性的管理。
答案 4 :(得分:0)
令人惊讶的是,有这么多人完全错误地认为这是错误的(例如Ziezi的回答)。当事情真的很简单时,人们似乎会使事情变得过于复杂。
在侵入式链接列表中,没有明确的“节点”结构/类。相反,“数据”结构/类本身包含指向链表中其他数据的下一个和上一个指针/引用。
例如(侵入式链表节点):
struct Data {
Data *next;
Data *prev;
int fieldA;
char * fieldB;
float fieldC;
}
注意下一个和上一个指针如何与实体的私有数据字段(例如fieldA)并排放置并插入。这“违反”了由标准链表强制执行的关注点分离(请参阅下文),但在大大减少查找特定节点的列表遍历量以及降低内存分配方面具有优势。
在侵入式链表中,“链表”本身通常是虚拟的,通常根本不需要创建链表struct / class。
相反,您可以简单地将指向第一个Data项的头指针存储在某些所有者/经理中。 该管理器还包含添加/删除功能,以根据需要更新指针。 有关更多信息,请参见https://gameprogrammingpatterns.com/spatial-partition.html
只有一对next / prev指针指示每个对象只能属于一个列表。但是,您当然可以根据需要添加多对next / prev指针(或定义next / prev指针数组)以支持多个列表中的对象。
在非侵入式(即标准)链接列表中,next / prev指针是专用“节点”实体的一部分,而实际数据实体只是该节点中的一个字段。
例如(非侵入式链表节点和数据):
struct Data {
int fieldA;
char * fieldB;
float fieldC;
}
struct Node {
Node *next;
Node *prev;
Data *data;
}
请注意下一个/上一个指针不会侵入实际的Data实体,并且保持关注点分离。
更新:
您可能会看到诸如https://www.data-structures-in-practice.com/intrusive-linked-lists/之类的其他站点使用“列表”结构(实际上是一个节点),该结构包含next / prev指针,并且是“数据”结构/类中的单个侵入字段。
这的确从数据中隐藏了下一个/上一个指针,但是它只需要简单地执行指针算术来访问与列表(节点)相关的实际数据,就会遇到麻烦。
这种方法在我的选择中增加了不必要的复杂性(仅直接直接嵌入next / prev字段),只是出于隐藏下一个/ prev指针的可疑目标。如果需要侵入式列表,请使其尽可能简单。 (此外,在托管内存语言中,无论如何都很难或不可能执行指针算术。)