-3

I'm trying to make a scan of an array where it follows the index with the numbers inside and I don't understand why it gives me this exception. I cant add any more details its a pretty straight forward question. this is a perfect scan for exsample this is NOT a perfect scan

using System;
                    
public class Program
{
    public static bool IsPerfect(int[] arr)
        {
            int next=0, done=0,i;

            while (done == 0)
            {
                i = arr[next];
                arr[next] = 10;
                next = arr[i];

                if (i == 0)
                    done = 1;
            }

            for(int j = 0; j < arr.Length; j++)            
                if (arr[j] != 10)
                    return false;               
            return true;

          
        }
        
    
    public static void Main()
        {
            int[] arr = { 3, 0, 1, 4, 2 };
            if (IsPerfect(arr) == true)
                Console.WriteLine("is perfect");
            if (IsPerfect(arr) == false)
                Console.WriteLine("boooo");

        }
}
  • 2
    You've said the _message_ of the exception (the title), but _where_ does the exception happen? What is the indexer at that time, and what is the contents of the array at that time? – gunr2171 Nov 02 '22 at 18:59
  • 4
    Debugger is your friend here - you can walk through it using the debugger – user1274820 Nov 02 '22 at 19:00
  • 4
    There are 5 elements in the array. In the 4th iteration of the `while (done == 0)` loop `i == 10` which is out of range here `next = arr[i];`. https://dotnetfiddle.net/YBDfBM – Retired Ninja Nov 02 '22 at 19:00
  • ok so how do you think i should fix it? – idan moalem Nov 02 '22 at 19:10
  • I don't get any error. But it is not "perfect" for the result either, though (with the given input). -- I'm going by the input in your code. That second array in your diagrams looks very suspicious. – topsail Nov 02 '22 at 19:12
  • As far as the error mentioned by Retired Ninja, this is probably not a solution that works if you have the same value in multiple elements of the array, and in any case you definitely cannot have a value in the array that is larger than the length of the array (you would go "next" to an element outside the bounds of the array). – topsail Nov 02 '22 at 19:14
  • 1
    Consider using a non-destructive way of flagging which elements have been visited. `bool[] visited = new bool[arr.Length];` If you hit duplicates, you don't get sent out of the array for an exception, and you can avoid an infinite loop; if at any point `visited[i]`is already `true`, you can immediately return `false` . At the end, the result would be `return visited.All(x => x);` – madreflection Nov 02 '22 at 19:16
  • 5
    (As a side note, it's deeply concerning that a teacher couldn't work this out.) – madreflection Nov 02 '22 at 19:21

3 Answers3

0

You are not specifying the functioning for duplicates... Use a method to check for duplicates and as soon as you encounter a duplicate element exit the loop... It will work fine!

Snehil Agrahari
  • 307
  • 1
  • 15
0

ok for anyone intrested the problem was lying in the second if, and the "next = arr[i];" the first i changed because it made more sense and the second and main problem was the other if. because i had the second condition it ran the method twice and with the changed values it returned an error. the solution was to put else instead.

0

Reverse engineering: we mark visited items and if all items are visted, then we have a "Perfect" array.

Problem: we mark item with 10 which can be an index (what if array has, say, 15 items)?

Solution: let's mark by -1 (definitely not an index - an array can have negative number of items) and check if item has been marked:

Tricky moment: we should assign -1 to the current arr[i] item but use its initial value to be assigned to i. Sure, we can save i and put it as

for (int i = 0; i >= 0 && i < arr.Length; ) {
  int nextI = arr[i];
  arr[i] = i;
  i = nextI;
}

but let's put in a short modern way: (i, arr[i]) = (arr[i], -1);

Code:

public static bool IsPerfect(int[] arr) {
  // In public method we must be ready for any input; null included 
  if (arr == null)
    return false; // or throw new ArgumentNullException(nameof(arr));

  // Do we have a valid array?
  for (int i = 0; i < arr.Length; ++i)
    if (arr[i] < 0 || arr[i] >= arr.Length)
      return false; 

  // Note the condition: we read the next item - arr[i] -
  // if and only if i is within range
  // Note, that we have nothing to increment / decrement
  for (int i = 0; i >= 0 && i < arr.Length; )
    (i, arr[i]) = (arr[i], -1); // note the assignment: both i and arr[i] in one go

  // We have marked all that we could. 
  // Do we have unmarked items? 
  for (int i = 0; i < arr.Length; ++i)
    if (arr[i] != -1) // ... yes, we have and thus 
      return false;   // arr is not perfect
      
  return true; 
}

Please, fiddle

Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215