Was tun gegen zu komplzierten Denken beim Programmieren

Darknet

Bekanntes Mitglied
Hallo,

Ich kann zwar einigermaßen Programmieren. Aber ich scheidere immer daran das ich viel zu komplziert denke. Wie lernt man das einfache Logische Denken? Gerade im Studium merke ich Programm Code eigentlich drei Zeiler ich will hochkomplex mit zig Metoden und Funktionen und dauert auch ewig. Wie lernt man das verdammt nochmal
 

White_Fox

Top Contributor
Übung...und Erfahrung.

Tipp: Nur ein stockfauler Ingenieur/Entwickler, ... ist ein guter Ingenieur/Entwickler.
Du mußt ein richtig fauler Hund werden, dann wirst du gut. Dann hörst du auf, mit großem Geschütz zu ballern wenn auch ein einfacher Dolch ausreicht und suchst dir automatisch den einfachsten Weg.

Setze Prioritäten beim Programmieren. Was ist dir wichtig an deinem Quellcode, was willst du erreichen? Soll er möglichst schnell laufen? Soll er möglichst kompakt sein?
Es ist übrigens NIE verkehrt, sich vor einer Arbeit einen Plan zu machen. Fünf Minuten UML, Klassendiagramm zeichnen oder wenigstens mal alle Anforderungen aufzuschreiben erspart eine Stunde frustrierende Fehlersuche. Mindestens. Gerade alle Anforderungen zu notieren ist sehr hilfreich, es ist der erste Schritt ein großes Problem in viele einfache Teilprobleme zu zerfleddern, die jedes für sich leicht zu lösen sind.

Ich habe ganz am Anfang auch gerne möglichst komplizierte Konstrukte gebaut, mit schön verschachtelten Ausdrücken. Stell dir einfach vor, du mußt den Code in zwei Jahren ändern. Und du wirst keine Ahnung mehr haben was du da gemacht hast und warum, der Code könnte auch von einem völlig Fremden geschrieben worden sein. Heute programmiere ich gern möglichst geschwätzig. Wenn ich den Quellcode wie eine Beschreibung lesen kann, dann bin ich mit meiner Arbeit zufrieden.

Und es gibt sie wirklich: die Wahnsinnigen, die ernsthaft versuchen, in einer Hochsprache auf Speicher und Rechenzeit zu optimieren. Schlage dir solche Gedanken aus dem Kopf, sofern du solche hast. Das ist ähnlich sinnvoll wie mit einem Stock die Flut zurückzudrängen.

Schaue dir öfter Arbeiten von anderen an. Hin und wieder sind da echte Perlen dabei, was Eleganz und Einfachheit betrifft. Und hast du dich schonmal mit Entwurfsmustern beschäftigt? Erst da lernst du so richtig, was an Klassenprogrammierung so klasse ist und wie man das geschickt anwendet. Ich kann dir "Entwurfsmuster von Kopf bis Fuß" (O'Reilly) dazu sehr empfehlen zu lesen.

Auch wenn ich das Buch ausdrücklich NICHT gut finde, so würde ich dir dennoch anraten es mal zu lesen: "Weniger schlecht programmieren" (O'Reilly).
 

LimDul

Top Contributor
Es ist noch kein Meister vom Himmel gefallen :)

Ich neige auch gerne dazu, zu komplexe Lösungen zu bauen. Ich habe das aber mittlerweile im Griff, dass ich mir rechtzeitig Feedback bei größeren Sachen von Kollegen einhole und generell mit Kollegen über den Code diskutiere. Da kommt man oft schnell drauf, dass es viel einfacher geht. Manchmal reicht es auch nur jemanden zu erklären, was man gemacht hat um zu merken, dass es einfacher geht.

Ich halte es auch am Anfang für eine natürliche Verhaltensweise. Man lernt so viele verschiedene Dinge kennen, verschiedene Algorithmen, Design-Patterns, die tollen Möglichkeiten der Vererbung, schicke Sprachfeatures und natürlich will man die alle anwenden. Da kommt man leicht in die Situation das man versucht ein Problem mit zig dieser Dinger zu erschlagen, obwohl es eine einfache, altmodische for-schleife mit int i als Zähler getan hätte. Was mir da hilft:

- Löse das Problem und nur das Problem. Versuche nicht gleich alle möglichen Erweiterungen vorauszudenken. Klar ist es toll, wenn man gleich an zukünftige Anforderungen denkt. Nur leider kommen diese Anforderungen dann doch nie oder in ganz anderer Form. Was nicht explizit aufgeschrieben ist, ist nicht gefordert. Punkt! (Das heißt nicht, dass man nicht zukunftssicher programmieren soll - das ist ein schmaler Grat)
- Erkläre in einfachen Worten jemanden was das Programm wie tut und wie jeder Teil dazu beiträgt. Und zwar bevor du fertig bist.
- Laufzeit und Optimierungen sind irrelevant. Die Lösung muss nicht hochperformant sein (Es sei denn, es wurde explizit gefordert). Solange man nicht gerade was mit expontieller Laufzeit baut oder in zeitkritischen Bereichen oder mit wirklich großen Datenmengen unterwegs ist, sind Laufzeiten der Algorithmen fast egal.
 

Darknet

Bekanntes Mitglied
zum Beispiel folgende Knobel Aufgabe werte 1 bis 6 man kann von 1 zu zwei und2 zu 1 gehen und soweite. Schritt für Schritt jetzt definiert man wieviele verschiedene Wege man gehen kann wenn man z.b insgesammt 10 Schritte gesammt gehen kann. Solche knobel aufgaben werden verlangt und die fallen mir schwer
 

mihe7

Top Contributor
zum Beispiel folgende Knobel Aufgabe werte 1 bis 6 man kann von 1 zu zwei und2 zu 1 gehen und soweite. Schritt für Schritt jetzt definiert man wieviele verschiedene Wege man gehen kann wenn man z.b insgesammt 10 Schritte gesammt gehen kann. Solche knobel aufgaben werden verlangt und die fallen mir schwer
Bei der Beschreibung fällt das jedem schwer.

Verstehe ich die Aufgabe richtig:

1. Es gibt ein Spielbrett mit 6 nebeneinander angeordneten Feldern
2. Eine Figur steht in einem dieser Felder
3. Die Figur wird in jedem Zug in ein benachbartes Feld bewegt
4. Die Frage ist, wie viele verschiedene Zugfolgen (Wege) es mit jeweils genau 10 Zügen höchstens geben kann?

Wenn das soweit stimmt, dann wäre die nächste Frage, ob Du nun ein Problem mit der Umsetzung in ein Programm hast oder das Problem in der mathematischen Lösung besteht?
 

Darknet

Bekanntes Mitglied
Also unter Zeitdruck fällt mir nicht ein, weiß dann nie wo wie ich anfangen muss.Jetzt hat mir einer etwas die Aufgabe erklärt aber ganz richtig hab ichs immer noch nicht:
Code:
private static int schritt(int n,int position){
        
        if(position == 0 && n>0) {
            
            return schritt(--n, ++position);
        }
        
        if(position == 5){ counter++;
        return 0;
        }
        
        if(n > 0 && position >0){
            System.out.println("Zahl: "+n+"Position: "+ position);
        return schritt(--n,++position)+schritt(--n,--position) ;
        }
        
        return 0;
    }
 

mihe7

Top Contributor
Also unter Zeitdruck fällt mir nicht ein, weiß dann nie wo wie ich anfangen muss.
Immer damit, das Problem zu analysieren. Bevor Du auch nur eine Zeile Code schreibst, musst Du das Problem verstehen(!)

Hier helfen mir meist Visualisierungen, daher habe ich oben von einem Spielbrett und einer Figur geschrieben, die zwischen den Feldern hin und her springen kann.

Damit kann man sich jetzt überlegen, dass die Figur auf jedem Feld höchstens zwei Möglichkeiten hat, sich zu bewegen: links (l) und/oder rechts (r). Eine Zugfolge aus 10 Zügen sieht dann z. B. so aus: "rrllrrllrr". Die Frage ist, wie viele Möglichkeiten hast Du, eine solche (gültige!) Zugfolge zu bilden?

Wie viele/welche Möglichkeiten gibt es, einen Zug auszuführen? Steht die Figur am Rand, kann die Figur jeweils nur einen Weg einschlagen (am linken Rand muss sie nach rechts gehen, am rechten Rand nach links), ansonsten gibt es zwei Möglichkeiten.

Wie viele/welche Möglichkeiten gibt es, zwei Züge hintereinander auszuführen? Für den ersten Zug gilt das eben geschriebene, d. h. 1 oder 2 Möglichkeiten. Für jeden der im ersten Zug eingeschlagenen Wege können für den zweiten, dritten, ... Zug die Möglichkeiten wieder nach dem gleichen Schema ermittelt werden: 1 oder 2, je nachdem, wo sich die Figur gerade befindet.

Daraus ergibt sich mal folgende Idee:
Code:
falls kein Zug möglich ist, ist die Anzahl der Wahlmöglichkeiten 0 -> ENDE
falls ein Zug nach links möglich ist, 
    ist für diesen(!) Weg die Anzahl der Wahlmöglichkeiten 1 zzgl. der für diesen(!) Weg noch folgenden Züge
falls ein Zug nach rechts möglich ist, 
    ist für diesen(!) Weg die Anzahl der Wahlmöglichkeiten 1 zzgl. der für diesen(!) Weg noch folgenden Züge
gib Gesamtzahl der Wahlmöglichkeiten zurück
Offensichtlich müssen die Kombinationsmöglichkeiten der beiden Wege addiert werden.

Das lässt sich dann in Code gießen:
Java:
private static int schritte(int n, int position) {
    if (n == 0) { // kein Schritt möglich
        return 0;
    } 

    int anzahl = 0;
    if (position > 0) { // es ist ein Schritt nach links möglich
        anzahl += 1 + schritte(n-1, position-1);
    }
    if (position < 6) { // es ist ein Schritt nach rechts möglich
        anzahl += 1 + schritte(n-1, position+1);
    }
    return anzahl;
}
Wenn ich jetzt also alles richtig verstanden und keinen Fehler gemacht habe, sollte das so passen.
 

MoxxiManagarm

Top Contributor
Übung...und Erfahrung.

Tipp: Nur ein stockfauler Ingenieur/Entwickler, ... ist ein guter Ingenieur/Entwickler.
Du mußt ein richtig fauler Hund werden, dann wirst du gut. Dann hörst du auf, mit großem Geschütz zu ballern wenn auch ein einfacher Dolch ausreicht und suchst dir automatisch den einfachsten Weg.

Wäre auch mein erster Tipp, besser könnte ich es kaum sagen :D Du willst so wenig Code wie möglich schreiben. Außerdem sollte dein Code verständlich und nachvollziehbar sein. Ist er es nicht, so ist es ein Indiz dafür, dass er zu umständlich ist. Meistens sind das Verschachtelungen von Schleifen, viele if-Bedingungen, Codeduplikate etc. die dazu führen. In den allermeisten Fällen gibt es dann kürzere Lösungsansätze. Wenn du also das Gefühl hast das trifft auf einen Codeabschnitt zu, dann schau dir genau diesen nochmal an. Aber ja, genau dieses Gefühl und anderes wächst definitiv mit der Erfahrung.

Immer damit, das Problem zu analysieren. Bevor Du auch nur eine Zeile Code schreibst, musst Du das Problem verstehen(!)

Hier helfen mir meist Visualisierungen

Und das ist auch mein 2. Tipp. Ein gutes Beispiel für gedankliche Visualisierungen sind m.E. immer LinkedLists. Viele tun sich bei diesen schwer, wir haben sehr viele Themen dazu hier im Forum. Wenn man sich eine LinkedList aber z.B. als Zug mit mehreren angekoppelten Waggons, eine Karawane mit mehreren Kamelen o.Ä. vorstellt, damm wird es deutlich einfacher.
Auch habe ich z.B. Snake Implementierungen gesehen, wo die Entwickler für die Bewegung jede Einheit verschieben. Wenn du dir aber immer gleiche Blöcke auf den Tisch vor dir stellst und du diese nach links verschieben sollst wirst du auch nicht jeden Block verschieben, sondern den rechten nehmen und ihn nach links tun..

Die Gedankenvisualisierung wird jedoch schwieriger bei Zuständen. Das ist der Punkt wo ich mir häufiger Tabellen oder Graphen aufmale um den Überblick zu behalten. Zustandsdiagramme sollten dir also geläufig sein, das lege ich dir ans Herz. UML's nutze ich selbst so gut wie nie.

3. Tipp: Ein richtig guter Code lässt sich fast "flüssig" lesen. Daher ist eine richtige Benennung auch sehr wichtig. Wenn du ein Problem in einer angelehnten Sprache für dich formulierst, dann brauchst du diese Formulierung nur noch in deine Hochsprache übersetzen. Die Formulierung braucht ein wenig Übung, aber das klappt irgendwann. Auch die Formulierung hilft dabei logische Ansätze zu finden. Beispiel:
Original: Max hat sich Silvester 2019 vorgenommen 1 Jahr lang jeden morgen ein Ei zu essen.
Umformuliert: Für jede Mahlzeit Typ Frühstück im Jahr 2020 isst Max ein Ei.
Pseudocode: For each meal in meals of 2020 esseEi() if meal is breakfest
(Ich hoffe es ist klar worauf ich hinaus will)
 
Zuletzt bearbeitet:

Darknet

Bekanntes Mitglied
Danke Mihe, aber die genaue Aufgabe geht noch anderster und zwar hat man die maximale Schritte vorgegeben und man soll quasie so lange von ein Schritt zum nächsten links oder rechts gehen bis entweder allle Schritte aufgebraucht sind oder man bei der 6 angekommen ist. Also quasi soll man die maximal Zahl an möglichen Wegen bis zur 6 herausfinden
 

Darknet

Bekanntes Mitglied
kannst du mir die Bedingung sagen ich doktor da jetzt schon wieder 2 Stunden rum.
Code:
if(position == 5){ counter++;
        
        },
das müsste es sein aber das gibt auch nur die Schritte zurück und nicht die wege. Dacht halt sobal es die End Position erreicht hat zähle hoch auch mit einen beendigenden return ändert das nix
 
Zuletzt bearbeitet:

Barista

Top Contributor
Nach meiner Meinung ist das gründliche Verständnis des zu lösenden Problems bzw. der Lösung der Schlüssel zur Einfachheit.

Wenn ich von einem Thema keine Ahnung habe, werden meine Programme meist riesig, wenn ich es verstanden habe meist kurz.

Ich habe mal einen Diff-Finder für Texte geschrieben (ich muss zugeben, damals kannte ich Levenshtein nicht). Das war ein Monster.

Im Java-Magazin stand dann irgendwann mal das Gleiche in weniger als 10 Zeilen.

Auch mein Expression-Parser war ziemlich groß, jemand anderes hatte das in weniger als 20 Zeilen erledigt.

Und meist ist kompliziert einfach nur falsch.

Das gilt auch für fachliche Anforderungen.

Der Ausdruck 'works an designed' bedeutet meist einen Spezifikationsfehler.


Eine andere Möglichkeit Einfachheit zu erreichen ist TDD, da darf man nicht zu viel implementieren.
 

mihe7

Top Contributor

Darknet

Bekanntes Mitglied
Hier ist die Aufgabe im Detail Buchstaben statt Zahlen

So lautet die richtige Aufgabe. Sorry ich dachte das wäre das selbe aber bei der Version kommen nich die in der AUfgabe genannten ergebnisse raus12847
 
Zuletzt bearbeitet:

mihe7

Top Contributor
Sorry, habe Dir vorher die Zahl der Schritte und nicht die der Wege genannt. Außerdem ist der Schritt nach rechts natürlich nur möglich, wenn position < 5 gilt.

Die Idee ist nun folgende: wenn Du beim letzten Schritt auf dem Buchstaben F landest, dann hast Du einen Weg gefunden. Ansonsten war der eingeschlagene Weg für die Tonne.

Beispiel:

Es sollen 2 Schritte verbleiben, Du stehst aktuell beim D. Dann gibt es zwei Möglichkeiten: nach links zum C oder nach rechts zum E. Egal, welchen Weg Du einschlägst, ist noch 1 Schritt zu gehen.

C gewählt: Im letzten Schritt kannst Du entweder zum B oder zurück zum D gehen. Bist Du zu B gegangen, hast Du keinen Weg gefunden (0), bist Du zu D gegangen, hast Du ebenfalls keinen Weg gefunden (0). Damit ist die Gesamtzahl der Wege für C = 0.

E gewählt: Im letzten Schritt kannst Du entweder zum F oder zurück zum D gehen. Bist Du zu F gegangen, hast Du einen Weg gefunden (1), bist Du zu D gegangen, hast Du keinen Weg gefunden (0). Damit ist die Gesamtzahl der Wege für E=1.

Da die möglichen Wege für C = 0 und für E = 1 sind, ist die Gesamtzahl der Wege für D = 1.

Java:
private static int schritte(int n, int position) {
    if (n == 0) { // es ist kein Schritt mehr möglich, dann
        return position == 5 ? 1 : 0; // wurde entweder ein (1) Weg gefunden, oder nicht (0)
    }

    int anzahl = 0;
    if (position > 0) { // es ist ein Schritt nach links möglich
        anzahl += schritte(n-1, position-1);
    }
    if (position < 5) { // es ist ein Schritt nach rechts möglich
        anzahl += schritte(n-1, position+1);
    }
    return anzahl;
}
 

Darknet

Bekanntes Mitglied
Keine Ahnung deine Idee ist Logisch und Nachvollziebar, aber ich komme nicht auf die Ergebnisse wie in der Aufgabe angegeben
 

mihe7

Top Contributor
Keine Ahnung deine Idee ist Logisch und Nachvollziebar, aber ich komme nicht auf die Ergebnisse wie in der Aufgabe angegeben
Ich schon. Der Parameter n entspricht nicht dem n aus der Aufgabe sondern dem 2n+5. Du darfst also nicht schritte(0, 0), schritte(1, 0) oder schritte(2, 0) aufrufen sondern musst schritte(5, 0), schritte(7, 0), schritte(9, 0) verwenden.
 

Darknet

Bekanntes Mitglied
Code:
    public static int wege(int n){
        
        int schritte = 2*n+5;
    //System.out.println(schritte);
    int anzahl = 0;
         schritt(schritte,0);
        return 1;
    }
    
    private static int schritt(int n,int position){
        if (n == 0) { // es ist kein Schritt mehr möglich, dann
        return position == 5 ? 1 : 0; // wurde entweder ein (1) Weg gefunden, oder nicht (0)
    }
        if (n == 0) { // kein Schritt möglich
        return 0;
        } 
        
        int anzahl = 0;
        if (position > 0) { // es ist ein Schritt nach links möglich
            anzahl += 1 + schritt(n-1, position-1);
        }
        if (position < 6) { // es ist ein Schritt nach rechts möglich
            anzahl += 1 + schritt(n-1, position+1);
        }
        //System.out.println("Anzahl: "+ anzahl);
        //System.out.println(position);
         
          return anzahl;
        }
Das hab ich schon :(
 

Darknet

Bekanntes Mitglied
Wie kann ich das mit der Rekusion gut lernen habe jetzt eine ähnliche Aufgabe wo ich auch wieder nicht weiter komme. Kann mich da nicht gut reindenken
 

White_Fox

Top Contributor
Noch ein Beispiel:

Java:
package main;

public class Rekursion {
    
    public static int rec(int i){
        if(i > 100){return i;} //Damit das nicht bis zur Unendlichkeit läuft...
        
        int j = ++i;
        return rec(j);
    }
    
    public static void main(String[] args) {
        System.out.println("Rekursive Methode rec() mit -100 aufrufen:");
        int i = rec(-100);
        System.out.println("Ergebnis von rec(): " + i);
    }
}
 

mihe7

Top Contributor
Wie kann ich das mit der Rekusion gut lernen habe jetzt eine ähnliche Aufgabe wo ich auch wieder nicht weiter komme. Kann mich da nicht gut reindenken
Du stellst Fragen... Jeder lernt doch anders. Ich finde, dass Datenstrukturen mit rekursiven Eigenschaften sehr anschaulich sind, insbesondere (Such-)Bäume. Visualisieren hilft oft und wie immer gilt: learning by doing.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
A Bei VierGewinnt fragen ob man gegen CPU oder Menschen spielen will. Java Basics - Anfänger-Themen 7
A Bei VierGewinnt vorher fragen, ob man gegen den Computer spielen möchte oder gegeneinander. Java Basics - Anfänger-Themen 1
A Bei VierGewinnt fragen, ob man gegen den Computer spielen möchte oder gegeneinander Java Basics - Anfänger-Themen 1
M Nach einer erstmaligen Eingabe, eine zweite Eingabe nur noch gegen bestätigung möglich Java Basics - Anfänger-Themen 2
V String Array gegen null-Eintrag sichern Java Basics - Anfänger-Themen 11
G gegen (etwas) programmieren Java Basics - Anfänger-Themen 11
C Reference - wird gegen meinen Willen - auf null gesetzt Java Basics - Anfänger-Themen 2
-horn- Strategie: Speichervorgang gegen unvollständiges Speichern absichern? Java Basics - Anfänger-Themen 11
S Implementierung gegen Interfaces / List, ArrayList, LinkedList Java Basics - Anfänger-Themen 11
O Neuen Blackberry 8800 oder Curve gegen kleines Programm Java Basics - Anfänger-Themen 9
A Programmieren gegen Interfaces Java Basics - Anfänger-Themen 4
L Was kann ich gegen "CMitarbeiterBeispiel has no main me Java Basics - Anfänger-Themen 5
F gegen interfaces programmieren Java Basics - Anfänger-Themen 6
A Logisches Denken?! Ihr seid gefragt. Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben