C# Collection - 按元素排序(旋转)
我有一个 IEnumerable
集合。假设它包含 5 个点(实际上它更像是 2000),
我想对这个集合进行排序,以便集合中的特定点成为第一个元素,所以它基本上是在特定点处切割集合并将它们重新连接在一起。
所以我的 5 点列表:
{0,0}, {10,0}, {10,10}, {5,5}, {0,10}
相对于索引处的元素重新排序3 将变为:
{5,5}, {0,10}, {0,0}, {10,0}, {10,10}
解决此问题的计算效率最高的方法是什么问题,或者是否存在已经存在的内置方法...如果是这样,我似乎找不到一个!
I have an IEnumerable<Point>
collection. Lets say it contains 5 points (in reality it is more like 2000)
I want to order this collection so that a specifc point in the collection becomes the first element, so it's basically chopping a collection at a specific point and rejoining them together.
So my list of 5 points:
{0,0}, {10,0}, {10,10}, {5,5}, {0,10}
Reordered with respect to element at index 3 would become:
{5,5}, {0,10}, {0,0}, {10,0}, {10,10}
What is the most computationally efficient way of resolving this problem, or is there an inbuilt method that already exists... If so I can't seem to find one!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在这种情况下,简单的数组复制是 O(n),这对于几乎所有现实世界的目的来说应该足够了。但是,我同意您在某些情况下 - 如果这是多级算法深处的一部分 - 这可能是相关的。另外,您是否只需要以有序的方式迭代该集合或创建一个副本?
链表很容易像这样重新组织,尽管访问随机元素的成本会更高。总体而言,计算效率还取决于您访问此项目集合的具体方式(以及它们是什么类型的项目 - 值类型还是引用类型?)。
标准.NET链接列表似乎不支持这种手动操作,但一般来说,如果您有一个链接列表,您可以按照您描述的方式轻松移动列表的各个部分,只需分配新的“下一个”和“上一个” " 指向端点的指针。
此处提供的集合库支持此功能:http://www.itu.dk/research/c5/< /a>.
具体来说,您正在寻找可在
LinkedList.View()
返回的对象上使用的LinkedList.Slide()
方法。A simple array copy is O(n) in this case, which should be good enough for almost all real-world purposes. However, I will grant you that in certain cases - if this is a part deep inside a multi-level algorithm - this may be relevant. Also, do you simply need to iterate through this collection in an ordered fashion or create a copy?
Linked lists are very easy to reorganize like this, although accessing random elements will be more costly. Overall, the computational efficiency will also depend on how exactly you access this collection of items (and also, what sort of items they are - value types or reference types?).
The standard .NET linked list does not seem to support such manual manipulation but in general, if you have a linked list, you can easily move around sections of the list in the way you describe, just by assigning new "next" and "previous" pointers to the endpoints.
The collection library available here supports this functionality: http://www.itu.dk/research/c5/.
Specifically, you are looking for
LinkedList<T>.Slide()
the method which you can use on the object returned byLinkedList<T>.View()
.没有枚举
list
两次的版本,但由于T[]
而消耗更高的内存:注意:添加参数检查。
Version without enumerating
list
two times, but higher memory consumption because of theT[]
:Note: Add argument checks.
ulrichb 所示的 Linq 方法的另一种替代方法是使用队列类(fifo 集合)将索引出队,并将已取出的索引入队。
Another alternative to the Linq method shown by ulrichb would be to use the Queue Class (a fifo collection) dequeue to your index, and enqueue the ones you have taken out.
使用 linq 的简单实现是:
这里发生的情况是,您执行了两次所需的比较来获取组合序列中的第一个元素。
该解决方案可读且紧凑,但效率不高。
其他贡献者描述的解决方案可能更有效,因为他们使用特殊的数据结构作为数组或列表。
The naive implementation using linq would be:
What happens here is that you perform twice the comparisons needed to get to your first element in the combined sequence.
The solution is readable and compact but not very efficient.
The solutions described by the other contributors may be more efficient since they use special data structures as arrays or lists.
您可以编写一个用户定义的 List 扩展,通过使用 List.Reverse() 进行旋转。我从 C++ 标准模板库中获取了基本思想,它基本上分三个步骤使用 Reverse: Reverse(first, mid) Reverse(mid, last) Reverse(first, last)
据我所知,这是最有效和最快的方式。我用 10 亿个元素进行了测试,旋转 Rotate(0, 50000, 800000) 需要 0.00097 秒。 (顺便说一句:向列表添加 10 亿个整数已经需要 7.3 秒)
这是您可以使用的扩展:
用法如下:
You can write a user defined extension of List that does the rotation by using List.Reverse(). I took the basic idea from the C++ Standard Template Library which basically uses Reverse in three steps: Reverse(first, mid) Reverse(mid, last) Reverse(first, last)
As far as I know, this is the most efficient and fastest way. I tested with 1 billion elements and the rotation Rotate(0, 50000, 800000) takes 0.00097 seconds. (By the way: adding 1 billion ints to the List already takes 7.3 seconds)
Here's the extension you can use:
The usage is like: