C#集合-按元素排序(旋转)
我有一个C#集合-按元素排序(旋转),c#,collections,C#,Collections,我有一个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} 解决这个问题的计算效率最高的方法是什么,或者是否有一种内置的方法已经存在。。。如果是这样,我似乎找不
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}
解决这个问题的计算效率最高的方法是什么,或者是否有一种内置的方法已经存在。。。如果是这样,我似乎找不到一个 在这种情况下,一个简单的数组拷贝是O(n),这对于几乎所有实际用途来说都足够好了。然而,在某些情况下——如果这是多层算法中的一部分——这可能是相关的。另外,您是否只需要以有序的方式迭代此集合,还是创建一个副本
var list = new[] { 1, 2, 3, 4, 5 };
var rotated = list.Skip(3).Concat(list.Take(3));
// rotated is now {4, 5, 1, 2, 3}
链表很容易像这样重新组织,尽管访问随机元素的成本更高。总的来说,计算效率还取决于您如何准确地访问此项集合(以及它们是什么类型的项—值类型还是引用类型?)
标准的.NET链表似乎不支持这种手动操作,但一般来说,如果您有一个链表,只需将新的“下一个”和“上一个”指针指定给端点,就可以按照您描述的方式轻松地在列表的各个部分移动
此处可用的集合库支持以下功能:。
具体地说,您正在寻找LinkedList.Slide()
方法,您可以在LinkedList.View()
返回的对象上使用该方法。在这种情况下,简单的数组副本是O(n),这对于几乎所有实际用途来说都足够了。然而,在某些情况下——如果这是多层算法中的一部分——这可能是相关的。另外,您是否只需要以有序的方式迭代此集合,还是创建一个副本
链表很容易像这样重新组织,尽管访问随机元素的成本更高。总的来说,计算效率还取决于您如何准确地访问此项集合(以及它们是什么类型的项—值类型还是引用类型?)
标准的.NET链表似乎不支持这种手动操作,但一般来说,如果您有一个链表,只需将新的“下一个”和“上一个”指针指定给端点,就可以按照您描述的方式轻松地在列表的各个部分移动
此处可用的集合库支持以下功能:。
具体地说,您正在寻找
LinkedList.Slide()
可用于LinkedList.View()
返回的对象的方法ulrichb显示的Linq方法的另一种替代方法是使用队列类(fifo集合)对索引进行出列,并将您取出的文件排队。ulrichb显示的Linq方法的另一种替代方法是使用队列类(fifo集合)将您的索引排队,并将您取出的文件排队。版本未枚举列表两次,但由于T[]
,内存消耗更高:
public static IEnumerable<T> Rotate<T>(IEnumerable<T> source, int count)
{
int i = 0;
T[] temp = new T[count];
foreach (var item in source)
{
if (i < count)
{
temp[i] = item;
}
else
{
yield return item;
}
i++;
}
foreach (var item in temp)
{
yield return item;
}
}
[Test]
public void TestRotate()
{
var list = new[] { 1, 2, 3, 4, 5 };
var rotated = Rotate(list, 3);
Assert.That(rotated, Is.EqualTo(new[] { 4, 5, 1, 2, 3 }));
}
公共静态IEnumerable旋转(IEnumerable源,int计数)
{
int i=0;
T[]温度=新的T[计数];
foreach(源中的var项)
{
如果(i
注意:添加参数检查。版本不枚举列表
两次,但由于T[]
,内存消耗更高:
public static IEnumerable<T> Rotate<T>(IEnumerable<T> source, int count)
{
int i = 0;
T[] temp = new T[count];
foreach (var item in source)
{
if (i < count)
{
temp[i] = item;
}
else
{
yield return item;
}
i++;
}
foreach (var item in temp)
{
yield return item;
}
}
[Test]
public void TestRotate()
{
var list = new[] { 1, 2, 3, 4, 5 };
var rotated = Rotate(list, 3);
Assert.That(rotated, Is.EqualTo(new[] { 4, 5, 1, 2, 3 }));
}
公共静态IEnumerable旋转(IEnumerable源,int计数)
{
int i=0;
T[]温度=新的T[计数];
foreach(源中的var项)
{
如果(i
注意:添加参数检查。使用linq的简单实现是:
IEnumerable x = new[] { 1, 2, 3, 4 };
var tail = x.TakeWhile(i => i != 3);
var head = x.SkipWhile(i => i != 3);
var combined = head.Concat(tail); // is now 3, 4, 1, 2
这里发生的事情是,为了得到组合序列中的第一个元素,需要执行两次比较。
该解决方案可读性强,结构紧凑,但效率不高。
其他贡献者描述的解决方案可能更有效,因为他们使用特殊的数据结构作为数组或列表。使用linq的简单实现是:
IEnumerable x = new[] { 1, 2, 3, 4 };
var tail = x.TakeWhile(i => i != 3);
var head = x.SkipWhile(i => i != 3);
var combined = head.Concat(tail); // is now 3, 4, 1, 2
这里发生的事情是,为了得到组合序列中的第一个元素,需要执行两次比较。
该解决方案可读性强,结构紧凑,但效率不高。
其他参与者描述的解决方案可能更有效,因为他们使用特殊的数据结构作为数组或列表。您可以编写一个用户定义的列表扩展,该扩展使用List.Reverse()进行旋转。我从C++标准模板库中提取了基本思想,基本上使用了三个步骤的反向:反向(第一,中间)反向(中间,最后)反向(第一,最后)
据我所知,这是最有效、最快的方法。我测试了10亿个元素,旋转(0,50000,800000)需要0.00097秒