之字形,IndexOutOfRangeException

时间:2019-03-05 12:54:13

标签: c# algorithm cryptography

我有一个问题。我尝试实现Zig-Zag算法(Rail Fence)。

enter image description here

我的代码如下:

    int n = 3; 
    int j = 0;
    int charCounter = 0;
    char[,] chars = new char[n, input.Length]; //array to store chars

    while(charCounter <= input.Length) //char counter related to input string
    {
        if (charCounter >= input.Length)
            break;

        chars[nCounter++, j++] = input[charCounter++]; //goes n = 0 => 1 => 2 => 3
        if (nCounter == n)
            for (int i = nCounter; i >= 0; i--) //from this loop, i want to go n => 3 => 2 => 1 => 0 etc
            {
                if (charCounter >= input.Length)
                    break;
                if (nCounter == 0)
                    continue;
                chars[--nCounter, j++] = input[charCounter++];
            } //here i get an exception
    }

从上面的示例中,我得到一个Exception

  

System.IndexOutOfRangeException:“索引在数组的边界之外。”

我的问题是,我的代码中哪里有错误?

当我从下面更改嵌套的for循环中的行时: chars[--nCounter, j++] = input[charCounter++];

对此:chars[nCounter--, j++] = input[charCounter++];

我没有收到任何异常,但是我的char数组看起来像这样:

char[0,0] = input[0];
char[1,1] = input[1];
char[2,2] = input[2];
char[2,3] = input[3]; //that is wrong, should be [1,3]
char[1,4] = input[4];
//and so on..

它应该像这样:

char[0,0] = input[0];
char[1,1] = input[1];
char[2,2] = input[2];
char[1,3] = input[3]; //here the diffrence
char[0,4] = input[4];
//and so on..

感谢您提出任何改进我的代码的建议!

编辑: 根据评论,我做了一些改进:

for(int i = 0; i <= input.Length; i++)
    chars[i % n, i] = input[i];

按行迭代工作还可以,现在我需要解决列问题

2 个答案:

答案 0 :(得分:1)

最困难的部分是生成递增然后递减的部分。由于没有简单的数学解决方案来生成从0到N然后再减小到0的数字序列。
我们将不得不 手动生成地图:

从0开始,增加直到我们达到N-1,减少直到我们达到0。对每个字符重复一次。

对于TestInput =“ abcdef”且级别= 3,我们有:

input    a b c d e f
index    0 1 2 1 0 1

然后我们按索引对这2个分组并排序:

index  inputs
  0     a,e
  1     b,d
  2      c 

我们有Select之后的{a,e,b,d,c}早午餐。一个简单的字符串构造函数,它接受char数组,然后得到结果字符串。

static string ZigZag(string input, int level)
{
    var indexMap = new List<int>();
    var tempIndex = 0; bool isIncreasing = true;
    for (int i = 0; i < input.Length; i++)
    {
        indexMap.Add(tempIndex);
        if (isIncreasing)
        { // Zig
            tempIndex++;
        }
        else
        {  // Zag
            tempIndex--;
        }

        if (tempIndex == level - 1)
        {
            isIncreasing = false;
        }

        if (tempIndex == 0)
        {
            isIncreasing = true;
        }
    }

    var result =
            input.Select((c, i) => new { Char = c, Index = indexMap[i] })
                .GroupBy(x => x.Index)
                .OrderBy(g => g.Key)
                .SelectMany(x => x.Select(y => y.Char))
                .ToArray();

    return new string(result);
}

答案 1 :(得分:1)

有一种方法可以生成从0到N递减到0的数字序列。
请考虑以下内容:
对于N = 2,序列为{0,1,0,1 ..}
对于N = 3,序列为{0,1,2,1,0,1,2 ..}

如果我们有一个像这样的序列,其模数为N + 1 ** ,我们可以枚举那些:
对于N = 3,{0,1,2,1}
对于N = 4,{0,1,2,3,2,1}

要生成此序列,我们必须: 从0到N计数。 然后从N-1计数到0 + 1。并将两者结合在一起。

static int[] GenerateIncreasingDecreasing(int level)
{
    var tempRange = Enumerable.Range(0, level).ToArray();
    var indexMap = (tempRange.Length < 2) ?
                    tempRange :
                    tempRange.Concat(Enumerable.Range(1, level-2).Reverse());
    return indexMap.ToArray();
}

那么加密功能将是:

static string ZigZag(string input, int level)
{
    var indexMap = GenerateIncreasingDecreasing(level);
    var result =
            input.Select((c, i) => new { 
                    Char = c, 
                    Index = indexMap[i % ((level>2)?(level + 1):level)] 
                })
                .GroupBy(x => x.Index)
                .OrderBy(g => g.Key)
                .SelectMany(x => x.Select(y => y.Char))
                .ToArray();

    return new string(result);
}

** :对于N <2,没有重复。因此,模数必须为N。