dynamisches int-Array, Beispiel Collatz-Problem



  • Zum 100. Geburtstag des Mathematikers Lothar Collatz wollte ich ein kleines Programm schreiben zum Collatz-Problem.

    Dazu nimmt man einfach eine beliebige natürliche Zahl. Ist diese gerade halbiert man diese. Ist sie ungerade wird sie mit 3 multipliziert und mit 1 addiert. Das tut man bis die Zahl 1 rauskommt immer wieder.

    Nun wollte ich als kleinen Test eine Funktion schreiben die als Parameter die Zahl nimmt und als Rückgabewert ein Array zurückgibt, mit der resultierenden Zahlenfolge.

    Problem nun ist das Array dessen Größe ja erst während der Laufzeit bekannt wird. genau genommen erst nach dem Durchlauf.

    Ich habs erst mal ohne array probiert und die Zahlenfolge ausgegeben. Das hab ich schon mal hinbekommen.
    Habe einfach eine do while-Schleife verwendet und in dieser mit dem Modulo-Operator in einer if-else-Verzweigung auf gerade oder ungerade getestet.

    do
    {
       if (zahl % 2 == 0
          zahl = zahl / 2;
       else
          zahl = (zahl * 3) + 1;
    }
    while (zahl != 1);
    

    Im nächsten Schritt wollte ich dies nicht auf der Console ausgeben, sondern im array speichern.

    static void Main(string[] args)
    {
       int zahl = 7;
       int index = 0;
       int[] arr = new int[100]; 
    
       do
       {
          if (zahl % 2 == 0)
          {
             zahl /= 2;
             arr[index] = zahl;
          }
          else
          {
             zahl = (zahl * 3) + 1;
             arr[index] = zahl;
          }
          index++;
       }
       while (zahl != 1);
    
       // Testausgabe:
       for (int i = 0; i < 100; i++)
          Console.Write(arr[i] + " ");
    }
    

    Nun will ich das ganze dynamisch machen. Nur klappt das nicht, da ich ja die Größe des Arrays erst am Ende der do-while-Schleife kenne, aber innerhalb des array schon auf das array zugreifen muss.

    Wie stell ich das an? Vielen dank schon vorher für die Antwort(en).
    Grüße



  • Das einfachste ist, du benutzt eine List<int> da kannst du dynamisch Items reinhauen und wieder löschen ohne dir Sorgen über die Größe zu machen.



  • Generics wollen deine Freunde werden ...



  • supi danke, das funktioniert bereits:

    static void Main(string[] args)
            {
                const int max = 10;
    
                for (int i = 1; i < max; i++)
                {
                    List<int> liste = new List<int>();
                    int zahl = i;
                    liste.Add(zahl);
                    do
                    {
                        if (zahl % 2 == 0)
                        {
                            zahl /= 2;
                            liste.Add(zahl);
                        }
                        else
                        {
                            zahl = (zahl * 3) + 1;
                            liste.Add(zahl);
                        }
                    }
                    while (zahl != 1);
    
                    //Ausgabe aller Zahlen:
                    for (int j = 0; j < liste.Count; j++)
                    {
                        Console.Write(liste[j] + " ");
                    }
                    // Anzahl der Zahlen in der Liste:
                    Console.WriteLine(" (" + liste.Count + ")");
                }
            }
    

    nun wollt ich das in eine Funktion packen. Als Rückgabetyp wär doch hier ein normales array am besten oder? Als Parameter nehm ich einfach die zahl. Was meint ihr?



  • Nimm doch als Rückgabewert eine List<int>.

    Das hier:

    int zahl = i;
    

    Ist meines erachtens nicht nötig.



  • Man kann hier auch wunderbar IEnumerable<T> und yield anwenden.
    🙂

    using System;
    using System.Collections.Generic;
    
    class Program
    {
        static void Main(string[] args)
        {
            ulong input;
            while (!ulong.TryParse(Console.ReadLine(), out input));
    
            var seq = collatz(input);
            foreach (var i in seq)
                Console.WriteLine(i);
    
            Console.ReadLine();
        }
    
        static IEnumerable<ulong> collatz(ulong seed)
        {
            yield return seed;
            while (seed > 1)
            {
                if (seed % 2 == 0)
                    seed /= 2;
                else
                    seed = 3 * seed + 1;
                yield return seed;
            }
        }
    }
    


  • Die Rückgabe als IEnumerable<T> ist hier vmtl. am Besten (oder als ReadOnlyCollection), da der Aufrufer deiner Funktion keine Möglichkeit braucht/haben soll, die berechnete Liste zu verändern... außer natürlich er macht new List<int>(collatz(10)); 😉 Das ist dann sein Bier.



  • Firefighter schrieb:

    Nimm doch als Rückgabewert eine List<int>.

    Das hier:

    int zahl = i;
    

    Ist meines erachtens nicht nötig.

    Ich denk schon, dass ich das machen muss, da ja sonst eine Endlosschleife habe.

    Im Code von Ausbeuter sind für mich viele neue Sachen drin, die ich noch nicht kenne bzw auch mit MSDN nicht verständlich sind. Neu für mich sind hier IEnumerable<T> sowie TryParse und yield. Wie ich erfahren hab ist IEnumerable eine Schnittstelle. Damit hab ich noch gar keine Erfahrungen. Leider steht auch in meinem C#-Buch dazu nix weiter.



  • Ahh ja ich sehs, hast recht du brauchst das, mein Fehler sorry.


Anmelden zum Antworten