【问题标题】:Reverse an array exercise...solution works but mine doesn't. Why?反转数组练习...解决方案有效,但我的无效。为什么?
【发布时间】:2018-11-10 19:38:03
【问题描述】:

我正在阅读这本书“The C# Player's Guide”并进入“试试看!”数组章节中的部分。

说明如下:

"创建 3 种方法:一种用于创建数组,一种用于反转数组,另一种用于在末尾打印数组。您的 main 方法将如下所示:

static void Main(string[] args)
{
        int[] numbers = GenerateNumbers();
        Reverse(numbers);
        PrintNumbers(numbers);
}

GenerateNumbers 方法应该返回一个包含 10 个数字的数组。

PrintNumbers 方法应该简单地使用 for 或 foreach 循环遍历数组,一次一个,并打印出其中的项目。

Reverse 方法将是最难的。试一试,看看你能做到什么。如果您遇到困难,这里有一些提示:

提示 1:要交换 2 个值,您需要将一个变量的值放在一个临时位置以进行交换:

//Swapping a and b.
int a = 3;
int b = 5;

int temp = a;
int a = b;
int b = temp;

提示 2:获取要交换的正确索引可能是一个挑战。使用 for 循环,从 0 开始一直到数组的长度 / 2。您在 for 循环中使用的数字将是要交换的第一个数字的索引,另一个将是数组的长度减去索引减去 1。这是为了说明数组是从 0 开始的。所以基本上,你将用 array[arrayLength - index - 1] 交换 array[index]。"

说了这么多,这是我目前的代码:

static void Main(string[] args)
{
        int[] numbers = GenerateNumbers();
        Reverse(numbers);
        PrintNumbers(numbers);
}

// Generates array of numbers and returns array
static int[] GenerateNumbers()
{
        int[] numbers = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        return numbers;
}

// Reverses array to print backwards from 10 to 1
static void Reverse(int[] numbers)
{
        for (int index = 0; index < numbers.Length; index++)
        {
            //swapping array indexes
            int a = numbers[index];
            int b = numbers.Length - index - 1;

            //temp array temporarily holds value while swapping indexes
            int temp = a;
            a = b;
            b = temp;
        }
}

// Prints numbers in array after order has been reversed
static void PrintNumbers(int[] numbers)
{
        for (int index = 0; index < numbers.Length; index++)
        {
            Console.WriteLine(numbers[index]);
        }

        Console.WriteLine();
}

我的代码再次以数字顺序而不是反向打印数组。这是书中反向方法的解决方案:

static void Reverse(int[] numbers)
    {
        // Initialize one index at the start of the array, and another
        // at the end of the array. The index of the last item in the
        // array is the length of the array - 1.
        int firstIndex = 0;
        int secondIndex = numbers.Length - 1;

        while (firstIndex < secondIndex)
        {
            // To swap two numbers, we need to copy one value out
            // to a safe place so that it doesn't get overwritten.
            int temp = numbers[firstIndex];
            numbers[firstIndex] = numbers[secondIndex];
            numbers[secondIndex] = temp;

            // Move on to the next pair.
            firstIndex++;
            secondIndex--;
        }
    }

奇怪的是他们使用 while 循环而不是 for 循环作为指令状态。

有人可以帮我了解我的代码哪里出了问题和/或如何翻译他们的 while 语句以用作我的 for 循环吗?

【问题讨论】:

  • 您正在交换 a 和 b 但没有将它们放回数组中......
  • 使用 Visual Studio 自带的 AWESOME Step Debugger 可以轻松解决这些谜题
  • 另外,a 是您数组中的一个值,但 b 只是另一个值的索引。
  • 除了下面给出的答案中的代码更正之外,请注意您的 for 循环在每一步中的作用。尝试找出正确解决方案中while 循环在哪个条件下结束,并将其与for 循环结束的条件进行比较。如果您遇到困难,请像使用计算机一样自己练习您的代码(是的,您就是那台奴隶般地执行代码的计算机)。在你的桌子上使用几个对象并将它们排成一行(这就是你的阵列)。跟踪index 变量(无论是在纸上还是在您的脑海中),然后盲目地执行您的代码。你会看到会发生什么;-)
  • @elgonzo 我实际上就是这样做的哈哈......然后我复制了给出的示例,用于从使用单独文件中的数组的指令中反转顺序,以查看它们是否正确反转。但是,它不会将更改应用回数组。而且我不完全确定该怎么做。

标签: c# arrays .net


【解决方案1】:

在您的代码中:

int a = numbers[index];
        int b = numbers.Length - index - 1;

        //temp array temporarily holds value while swapping indexes
        int temp = a;
        a = b;
        b = temp;

您将数字本身放入 a,同时将最后一个索引放入 b(不是最后一个索引处的数字)。应该是这样的:

        int tmp = numbers[index];
        numbers[index] = numbers[numbers.Length - index - 1];
        numbers[numbers.Length - index - 1] = tmp;
    }

而且你的 for 循环必须遍历数组的一半,因为更进一步,会再次将它们交换到原来的位置:

for(int i=0;i<number.Length/2; i++)
{
     int tmp = numbers[index];
     numbers[index] = numbers[numbers.Length - index - 1];
     numbers[numbers.Length - index - 1] = tmp;
}

如果将它们分配给ab,则应将它们放回(numbers[numbers.Length-index-1]=a; numbers[index]=b;),因为在分配它们时,数组中的值将复制到ab,而不是引用(它们在内存中的地址)

【讨论】:

  • 观看for 循环 :-) OP 的代码在到达数组中心时不会停止迭代,而是一直迭代到数组的最后,本质上是交换回交换的元素(假设你的应用代码更正)
  • @Tonyobyo,感谢 elgonzo,您的代码中还有另一个问题。我编辑了我的答案,请看答案的最后部分。
  • @Tonyobyo,此处答案中提供的代码将交换数组中的元素。不知道你还需要弄清楚什么......
  • @Tonyobyo 是的,如果你将它们分配给ab,那么你应该把它们放回去(numbers[numbers.Length-index-1]=a; numbers[index]=b;1);在分配它们时,数组中的值被复制到ab,而不是引用(它们在内存中的地址)。
【解决方案2】:

如果我要反转一个数组,我会这样做,因为我认为它更简单、更干净:

//new array to hold reverse 
int[] rev = new int[fwd.Length];
//establish an indexer variable for fwd and reverse
//variable f starts at 0 and goes to length -1
//variable r goes the other way
for(int f = 0, r = rev.Length - 1; f < fwd.Length; f++, r--)
  rev[r] = fwd[f];

return rev;

我很欣赏您的算法,将早期条目与后来的条目交换,沿数组返回到一半,但它的数学和变量赋值非常繁重,似乎在例如“位置2的数组值”和“计算位置2的对应位置”

我个人认为声明另一个相同大小的数组并将内容复制到其中更简单,当您向前读取源数组时向后工作 - 这种方法在实施时可能更无缺陷。

通常必须考虑代码的可读性、可理解性和可维护性以及其他因素。始终努力编写简单且不言自明的代码,即使以绝对的性能为代价。当你挠头说“为什么这个复杂的意大利面条工作?”或者更糟糕的是,对于其他人来说,通过优化一些微小的代码获得的微秒很容易浪费在几个小时或几天内代码并说“这应该做什么,为什么它不起作用?”

您还询问了他们的 while 循环将如何转换为您的 for 循环。这是一个for循环:

for(setup; test; post-loop-actions)

在他们的代码中:

static void Reverse(int[] numbers)
{
    // setup
    int firstIndex = 0;
    int secondIndex = numbers.Length - 1;

    // test
    while (firstIndex < secondIndex)
    {
        //post-loop-actions
        firstIndex++;
        secondIndex--;
    }
}

因此他们的 while 循环,翻译成一个 for 循环:

static void Reverse(int[] numbers)
{
    // setup
    for(
        int firstIndex = 0, secondIndex = numbers.Length - 1; //setup
        firstIndex < secondIndex;                             //test
        firstIndex++, secondIndex--                           //post-loop-actions
    )
    {
        ...

    }
}

我将 for 循环花括号部分分成 3 行;如果 while 循环示例中的变量名更短,它可能更适合在线

您可以在 for loop setup/post-loop-action 中执行多个赋值,方法是用逗号分隔语句。

这两种形式之间存在实际差异 - 在 while 循环形式中,变量在循环结构之外声明,并且在循环结束后仍可用于代码。

【讨论】:

  • 这是一个练习。如果有人需要这个,Array.Reverse已经实现了,完全不需要实现。
  • 对不起,我应该说“如果我要将数组反转作为学术练习”..
猜你喜欢
  • 2015-09-12
  • 1970-01-01
  • 1970-01-01
  • 2017-01-30
  • 2019-05-27
  • 1970-01-01
  • 2022-04-15
  • 2021-10-01
  • 2014-02-28
相关资源
最近更新 更多