如何在列表中移动数据

时间:2012-11-08 12:24:15

标签: c# algorithm linq list arraylist

我有以下情况,我希望得到一个没有大量循环和切片的通用解决方案。

首先:

我初始化N通过它我计算了列表大小(初始大小):

通过此等式N(N-1)/2 ..

假设我设置了N = 5,因此初始尺寸为10

之后我用一些方法用一个和零填充列表。

像这样:

  

0 1 0 1 1 1 0 1 0 1

此列表根据N进行分段,其中段为(N-1)。

所以

  • 第一段是:0 1 0 1
  • 第二段是:1 1 0
  • 第三段是:1 0
  • 和Forth Segment是:1
  

[0 1 0 1] [1 1 0] [1 0] [1]

我想要做的是,如果我再次输入任何数字作为输入N:

使用正确的移位保持以前的数据

根据新尺寸。例如,如果N = 6,那么尺寸将为15

所以我将有5个段而不是4个

我想这样:

  

[0 1 0 1 0 ] [1 1 0 0 ] [1 0 0 ] [1 0 ] [ 0 ]

反之,如果我首先输入N = 7并填充它。然后我输入N = 4

我想做出正确的转变

5 个答案:

答案 0 :(得分:2)

LinkedList似乎是最合适的收藏类。它使您能够从列表中的任何位置以恒定时间插入和删除元素。

下面给出了用于将N增加和减少一个的算法。两个操作都是O(N)。

// the whole list of integers
var data = new LinkedList<int>();

// stores the final node of each segment
var segmentEnds = new LinkedList<LinkedListNode<int>>();

/* INCREASING */
// increase all existing segments by one
var node = segmentEnds.First;
while (node != null)
{
    node.Value = data.AddAfter(node.Value, 0);
    node = node.Next;
}

// add the last segment of size 1
segmentEnds.AddLast(data.AddLast(0));

/* DECREASING */
if (data.Count > 0)
{
    // remove the last element from each segment
    node = segmentEnds.First;
    while (node != null)
    {
        var temp = node.Value.Previous;
        data.Remove(node.Value);
        node.Value = temp;
        node = node.Next;
    }

    // remove the last (now empty) segment
    segmentEnds.RemoveLast();
}

答案 1 :(得分:2)

您必须在一个列表中包含这些内容吗?看来你所拥有的是这里的n个列表的列表,因此创建一个大小为N的列表,其中包含大小为1到N的列表。这样,如果你增加N,你只需在每个列表中添加适当数量的0,并创建只有0英寸的新列表。如果你减少N,我不确定规则是什么,但我怀疑相比之下,你只需删除适当数量的短列表,然后删除其他列表中的最后一个元素。

它不具备单个arraylist的作用,但它是存储您描述的数据的更好方法,我会说。无论如何,你总是可以很容易地从我描述的模型中获得平坦的列表......

答案 2 :(得分:2)

也许您应该开始考虑二维并使用List<Segment>,而SegmentList<bool>。通过使用此功能,您应该能够轻松添加/删除段或以您喜欢的方式更改所有段。但这会以某种方式导致重度循环,但我认为如果不在任何级别上循环,你就无法解决这个问题。

答案 3 :(得分:1)

int N = 5;
var array = Enumerable.Range(1, N - 1).Select(i => Fill(i))
                      .SelectMany(x => x)
                      .ToArray();

int[] Fill(int len)
{
    int[] arr = new int[len];
    for (int i = 0; i < len; i++) arr[i] = 1; //Fill
    return arr;
}

答案 4 :(得分:1)

基本上,您使用一维列表建模2D数据结构。虽然它有些不正统,但通常会节省内存。

最简单的解决方案是在扩展或收缩列表时制作副本。当您需要缩短或扩展列表时,请创建目标大小的新列表,然后使用两个嵌套循环进行复制,就好像原始列表是2D数据结构一样。制作一个采用rowcolumnN的映射函数,并将索引返回到与{row, column}对对应的普通列表中可能会非常有帮助:

private static int MakeIndex(int r, int c, int N) {
    return (N*(N+1)-(N-r)*(N+1-r))/2+c;
}

现在,您可以将大小为{r, c}的列表中的N1对的索引转换为大小为N2的列表中同一对的索引。

您可以通过扩展和缩小来改进此解决方案。关键问题是你走的方向:收缩时,前后走;在扩张时,回到前面。