[英]In c#, how can i rotate a list a specific amount of places?
我编写了一个代码来将列表旋转特定数量的位置,下面的代码可以工作,但我想知道是否有更有效的方法来做到这一点。
public void Test8(List<int> items, int places)
{
int nums;
for (int i = 0; i < places; i++)
{
nums = items[items.Count() - 1];
items.RemoveAt(items.Count - 1);
items.Insert(0, nums);
}
}
这是一个经典的计算机科学问题。 一种稍微快一点的技术是反转整个数组,然后反转数组的两个块:
// 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) 时间,与移位大小无关。
如果您使用 Circular Array QUEUE(理论上它比列表具有更好的内存管理)来实现它,它可能会更快。 这不需要物理旋转现有数据,因此它应该比您的原始代码更快。
顺便说一句,您可以阅读 StackOverflow 中的其他参考资料来丰富您的知识,例如:
您正在插入和删除列表元素。 有一些与此相关的开销。 可以通过索引访问列表。 因此,您可以遍历列表,将元素移动到它们应该在的位置。您需要使用一个临时整数变量来避免覆盖任何列表数据。
检查并确保旋转不是无意义的也很好,即通过删除和添加项目 5K 次将长度为 3 的列表旋转 5K 是没有意义的,您可以通过执行类似places%=items.Count;
的操作来做到这一点places%=items.Count;
在开始旋转之前。
这是一个类似的问题: 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));
}
您可以编写用户定义的List<int>
扩展,使用List<T>.Reverse()
进行旋转。 我从 C++ 标准模板库中获取了基本思想,它基本上分三个步骤使用 Reverse: Reverse(first, mid) Reverse(mid, last) Reverse(first, last)
据我所知,这是最有效和最快的方式。 我测试了 10 亿个元素,旋转Rotate(0, 50000, 800000)
需要 0.00097 秒。 (顺便说一句:向 List 添加 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();
}
ArrayList 中指定次数的循环右移数组。 数组元素的指定范围和循环移位。 与数组实现相比,代码变得更快
代码
using System;
using System.Collections;
public class Program
{
// Circular Array repeting logic in ArrayList
public static ArrayList CircularshiftArry(ArrayList a, int circularrep)
{
int I = 1;
while (I <= circularrep)
{
int n = a.Count;
a.Insert(0, a[n - I]);
I++;
}
return a;
}
public static void Main()
{
Console.WriteLine("ENTER HOW MANY CIRCULAR REPETATION YOU WANT");
int circularrep = int.Parse(Console.ReadLine());
ArrayList a = new ArrayList();
Console.WriteLine("HOW MANY ARRAY ELEMENTS YOU WANT TO ENTER");
int num = int.Parse(Console.ReadLine());
for (int i = 0; i < num; i++)
{
Console.WriteLine("ENTER ARRAY ELEMENTS:{0}", i);
int p = int.Parse(Console.ReadLine());
a.Add(p);
}
Console.WriteLine("\n");
Console.WriteLine("The enterd array is :");
for (int i = 0; i < num; i++)
{
Console.Write("{0}\t", a[i]);
}
ArrayList b = CircularshiftArry(a, circularrep);
Console.WriteLine("\n");
int N = b.Count;
Console.WriteLine("The {0}times circular shifted array is :", circularrep);
for (int i = 0; i < N - circularrep; i++)
{
Console.Write("{0}\t", b[i]);
}
Console.ReadLine();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.