繁体   English   中英

在 c# 中,如何将列表旋转特定数量的位置?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM