我编写了一个代码来将列表旋转到特定数量的位置,我在下面的代码可以工作,但我想知道是否有更有效的方法来执行此操作。
{{1}}
答案 0 :(得分:1)
这是一个典型的计算机科学问题。一种稍微快一点的技术是反转整个阵列,然后反转阵列的两个块:
// If we want to shift two places, start with an array
[1, 2, 3, 4, 5, 6, 7, 8]
// Then reverse the entire array
[8, 7, 6, 5, 4, 3, 2, 1]
// Then reverse the first n elements, two in our case
[7, 8, 6, 5, 4, 3, 2, 1]
^^^^
// Then reverse the remaining items
[7, 8, 1, 2, 3, 4, 5, 6]
^^^^^^^^^^^^^^^^
或者,代码:
static void Reverse(List<int> items, int posFrom, int posTo)
{
// Helper to reverse a sub portion of an array in place
while (posFrom < posTo)
{
// Swap the first and last items
int temp = items[posFrom];
items[posFrom] = items[posTo];
items[posTo] = temp;
// Shrink down to the next pair of items
--posTo;
++posFrom;
}
}
static void Test8(List<int> items, int places)
{
// Sanity, if we try to rotate more than there are
// items in the array, it just loops around
places %= items.Count;
// Reverse the entire array
Reverse(items, 0, items.Count - 1);
// Reverse the first group of items
Reverse(items, 0, places - 1);
// Reverse the second group of items
Reverse(items, places, items.Count - 1);
}
这是O(n)时间,无论班次大小如何。
答案 1 :(得分:1)
如果使用循环数组QUEUE(理论上它具有比列表更好的内存管理)来实现它会更快。这不需要物理旋转现有数据,因此它应该比原始代码更快。
顺便说一下,您可以阅读StackOverflow中的其他参考资料,以丰富您的知识,例如:
答案 2 :(得分:0)
您正在插入和删除列表元素。有一些与此相关的开销。可以通过索引访问列表。因此,您可以遍历列表,将元素移动到它们应该处于的位置。您将需要使用临时整数变量来避免覆盖任何列表数据。
答案 3 :(得分:0)
也很好检查并确保旋转不是荒谬的,即通过移除和添加5K次项目来旋转长度为3的列表5K没有意义,你可以通过做{{1在开始旋转之前。
答案 4 :(得分:0)
这是一个类似的问题: C# Collection - Order by an element (Rotate)
另外,试试这个:
static void Main(string[] args)
{
var items = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var rotatedItems = Rotate(items, 4);
// rotated is now {5, 6, 7, 8, 9, 1, 2, 3, 4}
Console.WriteLine(string.Join(", ", rotatedItems));
Console.Read();
}
public static IEnumerable<int> Rotate(IEnumerable<int> items, int places)
{
return items.Skip(places).Concat(items.Take(places));
}
答案 5 :(得分:0)
您可以编写用户定义的扩展名List<int>
,该扩展名可以使用List<T>.Reverse()
进行旋转。
我从C ++标准模板库中获取了基本思想,该库主要通过三个步骤使用反向:
反转(第一,中)
倒退(中尾)
反转(第一个,最后一个)
据我所知,这是最有效,最快的方法。我测试了10亿个元素,旋转Rotate(0, 50000, 800000)
花费了0.00097秒。
(顺便说一句:向列表中添加10亿个整数已经需要7.3秒)
这是您可以使用的扩展名:
public static class Extensions
{
public static void Rotate(this List<int> me, int first, int mid, int last)
{
//indexes are zero based!
if (first >= mid || mid >= lastIndex)
return;
me.Reverse(first, mid - first + 1);
me.Reverse(mid + 1, last - mid);
me.Reverse(first, last - first + 1);
}
}
用法类似于:
static void Main(string[] args)
{
List<int> iList = new List<int>{0,1,2,3,4,5,6,7,8,9};
Console.WriteLine("Before rotate:");
foreach (var item in iList)
{
Console.Write(item + " ");
}
Console.WriteLine();
int firstIndex = 0, midIndex = 3, lastIndex = 5;
iList.Rotate(firstIndex, midIndex, lastIndex);
Console.WriteLine($"After rotate {firstIndex}, {midIndex}, {lastIndex}:");
foreach (var item in iList)
{
Console.Write(item + " ");
}
Console.ReadKey();
}