One would think the simple code
人们会想到简单的代码
llist1.Last.Next = llist2.First;
llist2.First.Previous = llist1.Last;
would work, however apparently in C#'s LinkedList, First, Last, and their properties are Get only.
可行,但显然在C#的LinkedList,First,Last中,它们的属性仅为Get。
The other method I could think of was
我能想到的另一种方法是
llist1.AddLast(llist2.First);
However, this does not work either - it fails because the first node of llist2 is already in a linked list.
但是,这也不起作用 - 它失败了,因为llist2的第一个节点已经在链表中。
Does this mean that I have to have a loop that manually AddLast's each node of llist2 to llist1? Doesn't this defeat the efficiency of linked lists????
这是否意味着我必须有一个循环,手动AddLast的llist2的每个节点到llist1?这不是打败链表的效率????
3 个解决方案
#1
16
Yes, you have to loop, unfortunately. This is an O(n) operation - O(1) for each entry added. There's no risk of requiring a buffer to be resized and copied, etc - although of course garbage collection might do roughly that :) You could even write handy extension methods:
是的,不幸的是,你必须循环。这是一个O(n)操作 - 添加的每个条目的O(1)。不存在需要调整缓冲区和复制等的风险 - 尽管当然垃圾收集可能大致如此:)您甚至可以编写方便的扩展方法:
public static class LinkedListExtensions
{
public static void AppendRange<T>(this LinkedList<T> source,
IEnumerable<T> items)
{
foreach (T item in items)
{
source.AddLast(item);
}
}
public static void PrependRange<T>(this LinkedList<T> source,
IEnumerable<T> items)
{
LinkedListNode<T> first = source.First;
foreach (T item in items)
{
source.AddBefore(first, item);
}
}
}
EDIT: Erich's comment suggests why you might think this is inefficient - why not just join the two lists together by updating the "next" pointer of the tail of the first list and the "prev" pointer of the head of the second? Well, think about what would happen to the second list... it would have changed as well.
编辑:Erich的评论建议你为什么认为这是低效的 - 为什么不通过更新第一个列表尾部的“下一个”指针和第二个列表头部的“prev”指针将两个列表连接在一起?好吧,想想第二个列表会发生什么......它也会发生变化。
Not only that, but what would happen to the ownership of those nodes? Each is essentially part of two lists now... but the LinkedListNode<T>.List
property can only talk about one of them.
不仅如此,但这些节点的所有权会发生什么?现在每个都基本上是两个列表的一部分......但LinkedListNode
While I can see why you might want to do this in some cases, the way that the .NET LinkedList<T>
type has been built basically prohibits it. I think this doc comment explains it best:
虽然我可以在某些情况下看到为什么你可能想要这样做,但是.NET LinkedList
The
LinkedList<T>)
class does not support chaining, splitting, cycles, or other features that can leave the list in an inconsistent state.LinkedList
)类不支持链接,拆分,循环或其他可能使列表处于不一致状态的功能。
#2
8
llist1 = new LinkedList<T>(llist1.Concat(llist2));
this concatenates the two lists (requires .NET 3.5). The drawback is that it creates a new instance of LinkedList, which may not be what you want... You could do something like that instead :
这连接了两个列表(需要.NET 3.5)。缺点是它创建了一个新的LinkedList实例,这可能不是你想要的......你可以这样做:
foreach(var item in llist2)
{
llist1.AddLast(item);
}
#3
4
Here you can find my linked list implementation with O(1) concat and split times.
在这里,您可以找到我的链表实现与O(1)concat和拆分时间。
Why .NET LinkedList does not support Concat and Split operations?
为什么.NET LinkedList不支持Concat和Split操作?
Short summary
简短的摘要
Advantages vs .NET LinkedList:
与.NET LinkedList的优点:
-
Less memory consumption, thus every node SimpleLinkedListNode has three pointers (prev, next, value) instead of four (prev, next, list, value) unlike original .NET implementation.
减少内存消耗,因此每个节点SimpleLinkedListNode有三个指针(prev,next,value)而不是四个(prev,next,list,value),这与原始的.NET实现不同。
-
Supports Concat and Split operations in O(1)
支持O(1)中的Concat和Split操作
-
Supports IEnumarable Reverse() enumerator in O(1) – by the way I do not see any reason why it’s not provided natively on the .NET LinkedList. Appropriate extension method requires O(n).
支持O(1)中的IEnumarable Reverse()枚举器 - 顺便说一下,我没有看到为什么它没有在.NET LinkedList上本地提供的原因。适当的扩展方法需要O(n)。
Disadvantages:
缺点:
- Does not support Count.
- 不支持Count。
- Concat operation leaves second list in an inconsistent state.
- Concat操作使第二个列表处于不一致状态。
- Split operation leaves original list in an inconsistent state.
- 拆分操作使原始列表处于不一致状态。
- You are able to share nodes between lists.
- 您可以在列表之间共享节点。
Other:
其他:
- I have chosen an alternative strategy for implementing enumeration and find operations, rather than more verbose and purely readable original implementation. I hope the negative performance impact remains insignificant.
- 我选择了一种替代策略来实现枚举和查找操作,而不是更详细和纯粹可读的原始实现。我希望负面的业绩影响仍然微不足道。
#1
16
Yes, you have to loop, unfortunately. This is an O(n) operation - O(1) for each entry added. There's no risk of requiring a buffer to be resized and copied, etc - although of course garbage collection might do roughly that :) You could even write handy extension methods:
是的,不幸的是,你必须循环。这是一个O(n)操作 - 添加的每个条目的O(1)。不存在需要调整缓冲区和复制等的风险 - 尽管当然垃圾收集可能大致如此:)您甚至可以编写方便的扩展方法:
public static class LinkedListExtensions
{
public static void AppendRange<T>(this LinkedList<T> source,
IEnumerable<T> items)
{
foreach (T item in items)
{
source.AddLast(item);
}
}
public static void PrependRange<T>(this LinkedList<T> source,
IEnumerable<T> items)
{
LinkedListNode<T> first = source.First;
foreach (T item in items)
{
source.AddBefore(first, item);
}
}
}
EDIT: Erich's comment suggests why you might think this is inefficient - why not just join the two lists together by updating the "next" pointer of the tail of the first list and the "prev" pointer of the head of the second? Well, think about what would happen to the second list... it would have changed as well.
编辑:Erich的评论建议你为什么认为这是低效的 - 为什么不通过更新第一个列表尾部的“下一个”指针和第二个列表头部的“prev”指针将两个列表连接在一起?好吧,想想第二个列表会发生什么......它也会发生变化。
Not only that, but what would happen to the ownership of those nodes? Each is essentially part of two lists now... but the LinkedListNode<T>.List
property can only talk about one of them.
不仅如此,但这些节点的所有权会发生什么?现在每个都基本上是两个列表的一部分......但LinkedListNode
While I can see why you might want to do this in some cases, the way that the .NET LinkedList<T>
type has been built basically prohibits it. I think this doc comment explains it best:
虽然我可以在某些情况下看到为什么你可能想要这样做,但是.NET LinkedList
The
LinkedList<T>)
class does not support chaining, splitting, cycles, or other features that can leave the list in an inconsistent state.LinkedList
)类不支持链接,拆分,循环或其他可能使列表处于不一致状态的功能。
#2
8
llist1 = new LinkedList<T>(llist1.Concat(llist2));
this concatenates the two lists (requires .NET 3.5). The drawback is that it creates a new instance of LinkedList, which may not be what you want... You could do something like that instead :
这连接了两个列表(需要.NET 3.5)。缺点是它创建了一个新的LinkedList实例,这可能不是你想要的......你可以这样做:
foreach(var item in llist2)
{
llist1.AddLast(item);
}
#3
4
Here you can find my linked list implementation with O(1) concat and split times.
在这里,您可以找到我的链表实现与O(1)concat和拆分时间。
Why .NET LinkedList does not support Concat and Split operations?
为什么.NET LinkedList不支持Concat和Split操作?
Short summary
简短的摘要
Advantages vs .NET LinkedList:
与.NET LinkedList的优点:
-
Less memory consumption, thus every node SimpleLinkedListNode has three pointers (prev, next, value) instead of four (prev, next, list, value) unlike original .NET implementation.
减少内存消耗,因此每个节点SimpleLinkedListNode有三个指针(prev,next,value)而不是四个(prev,next,list,value),这与原始的.NET实现不同。
-
Supports Concat and Split operations in O(1)
支持O(1)中的Concat和Split操作
-
Supports IEnumarable Reverse() enumerator in O(1) – by the way I do not see any reason why it’s not provided natively on the .NET LinkedList. Appropriate extension method requires O(n).
支持O(1)中的IEnumarable Reverse()枚举器 - 顺便说一下,我没有看到为什么它没有在.NET LinkedList上本地提供的原因。适当的扩展方法需要O(n)。
Disadvantages:
缺点:
- Does not support Count.
- 不支持Count。
- Concat operation leaves second list in an inconsistent state.
- Concat操作使第二个列表处于不一致状态。
- Split operation leaves original list in an inconsistent state.
- 拆分操作使原始列表处于不一致状态。
- You are able to share nodes between lists.
- 您可以在列表之间共享节点。
Other:
其他:
- I have chosen an alternative strategy for implementing enumeration and find operations, rather than more verbose and purely readable original implementation. I hope the negative performance impact remains insignificant.
- 我选择了一种替代策略来实现枚举和查找操作,而不是更详细和纯粹可读的原始实现。我希望负面的业绩影响仍然微不足道。