2d x² Array (Matrix) diagonal auffüllen



  • Hallo liebe Community;
    als kompletter Programmiertrottel hab ich angefangen C++ zu lernen.
    Jetzt stehe ich bei einer Übungsaufgabe auf dem Schlauch.
    Aufgabe ist eine quadratische Matrix diagonal aufzufüllen.
    also so soll das am ende aussehen bei zum Beispiel eine Matrix 5x5

    1  2  4  7  11
    3  5  8  12 16
    6  9  13 17 20
    10 14 18 21 23
    15 19 22 24 25
    

    jetzt muss das natürlich für eine x-beliebige Matrix x*x gelten.
    Ich habe mir gedacht nach dem Einlesen der größe erstelle ich die


    das es "über" der Diagonalen (von rechts oben(11) nach links unten(15))
    einen anderen Algroythmus benötigt als den auf der "rechten" Seite der Diagonalen.
    ergibt ja sinn da es dann wieder weniger Spalten aufzufüllen sind wo vorher mehr sind. Allerding steh ich seit heute morgen auf dem Schlauch und mir fällt nicht direkt ein wie ich das umsetzen kann.
    also ich werde wohl 3 Funktionen brauchen (1. die das Dreieck links über der diagonalen ausfüllt 2. die diagonale 3. rechts unter der diagonale.
    da die 3. Funktion ja quasi auf der 1. aufbaut sollte das nachdem ich die erste habe nicht mehr so schwierig sein.
    also zur ersten:
    nach einem Bsp 10x10 Array;

    #include <iostream>
    
    int main(){
    	int x=10;
    	int y=10;
    	int matrix[x][y];
    	for (int i = 0; i<x; i++) {
    		for (int j =0; j<y; j++){ // wollte nur sichergehen dass kein Ergebnis durch unbestimmte Speicherplätze gefälscht wird
    			matrix[i][j]=0;
    			}
    		}
    
    	int cntx,cnty; // 2 Hilfsvariablen zum hoch bzw. runterzählen
    	int i=1;
    	cntx=0;
    	cnty=0;
    	for(int max=0;max<x;max++){ // da die erste Zahl [0][0] die 2=[0][1] 3.=[01][0]... [0->max][max->0] 
    		cnty=max; // sozusagen y=[max->0] da muss ich ja am anfang auf max sezten
    		cntx=0;
    		while(cnty>=0){
    		matrix[cntx][cnty]=i;
    		i++;
    		cntx++;
    		cnty--;
    		}
    	}
    
    	//Ausgabe
    	for (int i = 0; i <x; i++) {
    		for (int j =0; j<y; j++){
    			std::cout<<matrix[i][j]<<"\t";
    			}
    			std::cout<<"\n";
    			}
    }
    

    Unterer Teil: der noch nicht funktioniert Segmentierungs fault:

    int i=x*x;
    	int cntx,cnty;
    	cntx=x;
    	cnty=x;
    	for(int max=x-1;max>0;max--){ 
    		cnty=y; 
    		cntx=x;
    		while(cnty>=0){
    		matrix[cntx][cnty]=i;
    		i--;
    		cntx--;
    		cnty++;
    		}
    	}
    

    Bitte nicht einfach irgendeinen Code hinschreiben von dem ich keine Ahnung habe wie er funktioniert ich will das ja lernen und vorallem verstehen.
    Habe mir schon diverse Tutorials und Bücher um die Ohren und Augen gehauen aber
    bis jetzt kam immer nur das ausfüllen von links nach rechts dran was aber in diesem Fall nicht geht bin also für jeden "Denkanstoß" bereit.

    Edit1: So der oben gepostete code hat mich beim Kommentare schreiben selber auf einen Fehler gebracht und jetzt funktioniert er. Es is ja sogar so, dass ich anscheinend gar nicht die Diagonale extra machen muss sondern der Code gibt mir schon das richtige Ergebniss aus also oberer Teil und die Diagonale selber jetzt muss ich nur aufpassen beim umdrehen das ich da die diagonale rauslasse obwohl da auchnichts passieren sollte weil ja theoretisch die gleichen zahlen darin stehen sollten 😉

    Edit2:

    unterer Teil:

    int i=x*x;
    	int cntx,cnty;
    	cntx=x;
    	cnty=x;
    	for(int min=x-1;min>0;min--){ 
    		cnty=min; 
    		cntx=x;
    		while(cntx>=min){
    		matrix[cntx][cnty]=i;
    		i--;
    		cntx--;
    		cnty++;
    		}
    	}
    

    funktioniert jetzt aber es kommt ein etwas seltsames ergebnis raus
    http://ideone.com/hCnE5L



  • So das problem hab ich gelöst jetzt funzt alles nur noch eine kleine Frage die ich bestimmt nach 100min auf google auch selber beantworten kann 😉
    will die ausgabe in eine funktion auslagern wie übergebe ich das Feld an die funktion

    void ausgabe(int matrix[int x][int x])
    

    würde die logischte Schlussfolgerung sein aber woher will die funktion dann wissen in den einzelnen dingen drinnen steht.
    außerdem habe ich irgendwo glaub ich gelesen das eine Funktion immer mit ddem original Feld arbeitet ergibt ja auch Sinn da sonst bei großen Feldern doppelt soviel Speicher anfällt...
    im inet hab ich die variante gefunden:

    int array[10][10];
    void passFunc(int a[][10])
    {
        // ...
    }
    passFunc(array);
    

    aber wie übergebe ich an Stelle der 10 die Variable x?


  • Mod

    Hier geht leider sehr viel schief und zwar schon im allerersten Schritt, wodurch dann der ganze Rest automatisch auch mit umfällt. Wie du da dein Array definiert hast, ist das kein C++. Du nutzt da ein spezielles Feature der Sprache C (sogenannte VLAs), die von einem gewissen C++-Compiler als Zusatzfeature für C++ unterstützt werden (oder eher: Man hat dieses Feature im C++-Modus des Compilers nicht absichtlich abgeschaltet). Viele C++-Compiler unterstützen dies nicht. Dein Code wird mit diesen Compilern nicht übersetzbar sein. Außerdem lernst du nicht, wie es in C++ richtig geht (C++ hat nämlich viel bessere Mechanismen).

    In C und C++ muss die Größe eines Arrays zur Compilezeit fest stehen, dass heißt, die Größenangabe muss ein Literal (z.B. int foo[5]; ) oder eine Konstante (z.B. const int size = 5; int foo[size]; . Wobei dies nur in C++ funktioniert, in C gelten Variablen trotz const als variabel) sein.

    In C gibt es seit dem Standard von 1999 (den aber einer der größten Compiler bis heute nicht umsetzt) auch die VLAs, mit denen man auch Variablen zur Größenangabe nutzen kann und dann eben erst zur Laufzeit bestimmt wird, wie groß das Array genau ist. Das Feature ist ein wenig problematisch, aus Gründen, die hier nicht wichtig sind und in der Folge, würde man ein VLA auch ganz anders einsetzen als hier. Aber da dies nicht das C-Forum ist, gehe ich da mal nicht weiter drauf ein, sondern sage nur, dass es so nicht geht.

    In C++ gibt es sehr viele Wege, ähnliches zu erreichen. Manche davon deutlich besser. Viele auch deutlich umständlicher, besonders die, die sich nur auf die allereinfachsten Sprachmittel beschränken. Ich habe den Eindruck, letzteres ist bei dir der Fall, oder? Die Nonplusultralösung würde alle dieser Stichworte benötigen: Klassen, std::vector, Templates, Operatorüberladung. Irgendwas davon schon einmal gehört? Zur Not kann man sich nämlich auch auf std::vector beschränken, aber wenn das alles ist, was man nutzen kann, dann wird es, wie erwähnt, ziemlich umständlich. Wohingegen die Lösung, bei der man aus dem Vollen schöpfen kann, sehr einfach zu benutzen wäre und dich, wenn man es ein einziges Mal gut macht, sogar für alle Zeit begleiten kann.

    Falls man nicht einmal std::vector zur Verfügung haben sollte, kann man sich diesen eventuell nachprogrammieren, wofür man aber wieder mindestens die gleichen Sprachfeatures bräuchte, die oben erwähnt wurden.

    Falls man weder std::vector hat, noch diesen nachprogrammieren kann, dann muss man darauf verzichten, die Größe der Matrix erst zur Laufzeit festzulegen. Dann muss man eben fest

    int matrix[10][10];
    

    schreiben. Dann funktioniert auch deine zweite Variante, die du im Netz gefunden hast*. Die erste Variante, die du dir selber ausgedacht hast, ist hingegen schlicht Unsinn. In C++ hat man auch die bessere Möglichkeit, statt dem rohen Array ein std::array zu nutzen. Technisch ist das das gleiche, aber anfängerfreundlicher in der Benutzung, da es die bösen Überraschungen vermeidet, die fast jeder Anfänger+ in C mit Arrays im Zusammenspiel mit Funktionen hat. Das wäre dann, da du ein std::array von std::arrays möchtest, ein geschachtelter Datentyp:

    std::array<std::array<int, 10>, 10> matrix;
    

    Ein typedef bietet sich an, wenn man das so benutzen möchte. Das kannst du dann auch ganz direkt an eine Funktion übergeben, so wie du es kennst, ohne die komischen Sonderverrenkungen für rohe Arrays. Das ist sogar einer der Hauptgedanken, warum es std::array gibt.

    💡 Falls du gerade nur Bahnhof verstehst, wäre es vielleicht eine gute Idee, darauf zu verzichten, die Matrix in einer Funktion zu füllen und stattdessen die Füllung ins Hauptprogramm zu schreiben. 💡

    *: Falls es nicht klar ist: Suche im Netz und Zusammenkopieren von Code ist nicht Programmieren. Code ist Logik pur; du musst von jedem Zeichen in deinem Programm genau wissen, wo und warum du es setzt! Es ist natürlich nicht verkehrt, im Netz zu suchen, wenn man Hilfe nötig hat, aber es ist wichtig, dass du die Hilfe auch verstehst und nicht nur kopierst. Gehe ich recht in der Annahme, dass du die VLAs auch irgendwo kopiert hast?
    Es ist irgendwie komisch, dass du diese Übungsaufgabe bekommen hast, obwohl anscheinend nicht die nötigen Sprachmittel durch genommen wurden. Das wirft kein gutes Licht auf den Lehrer bzw. das Lehrbuch. Leider ist das aber auch nichts neues, gerade im deutschsprachigen Raum gibt es sehr viel, sehr schlechtes Lehrmaterial zu C++. Meistens entweder von ahnungslosen Anfängern selber geschrieben oder von Leuten, die von 40 Jahren mal Fortran gelernt haben und nun denken, sie können C++, wenn sie nur print durch cout ersetzen. Wie lernst du C++?

    +: Zumindest die, mit schlechten Lehrbüchern/Lehrern. Ich habe den Eindruck, du gehörst dazu. Siehe meine Signatur für Empfehlungen zu guten (C++-)Büchern.


  • Mod

    Um mal ein bisschen auf dein Problem mit dem Füllen der Matrix einzugehen: Da gibt es so viele Wege, dass ich gerade selber gar nicht weiß, welchen ich am besten finde. Ich weiß nur, dass ich deinen Weg mit den drei Funktionen nicht mag. Wieso drei Funktionen? Sind es nicht eigentlich zwei? Eine für die obere linke Hälfte und eine für die untere rechte Hälfte. Die Diagonale ist doch kein Sonderfall, sondern für beide dieser Funktionen die natürliche Fortsetzung. Mit zwei Funktionen könnte ich mich anfreunden.

    Ein paar andere Ideen:

    • Drehen wir die Matrix mal ein wenig. Hast du schon einmal eine Raute ausgeben müssen? Das ist eine typische Übungsaufgabe:
    *
           *   *
         *   *   *
       *   *    *   *
     *   *   *    *   *
       *   *    *   *
         *   *   *
           *   *
             *
    

    Wenn ich da nun statt Sternchen Zahlen dran schreibe, dann ist das deine Matrix:

    1
           2   3
         4   5   6
       7   8    9   10
     11  12  13   14  15
       16  17   18  19
         20  21  22
           23  24
             25
    

    So kannst du deine Lösung zur Ausgabe einer Raute auf das Füllen der Matrix übertragen. Ich weiß nicht, wie du die Raute lösen würdest. Es gibt da auch die Möglichkeit, dies mit zwei verschiedenen Funktionen zu machen (hier ist noch offensichtlicher, dass drei Funktionen überflüssig sind), aber es gibt durchaus auch Lösungen, die alles in nur einem Rutsch schreiben können. Kannst du ja mal drüber nachdenken.

    • Originalmatrix:
    1  2  4  7  11
    3  5  8  12 16
    6  9  13 17 20
    10 14 18 21 23
    15 19 22 24 25
    

    Schreiben wir mal die Differenzen zwischen Zahlen auf, wenn wir eine Zahl mit der über ihr vergleichen:

    *  *  *  *  *
    2  3  4  5  5
    3  4  5  5  4
    4  5  5  4  3
    5  5  4  3  2
    

    Da gibt's ein Muster, wie du siehst. Ebenso, wenn wir eine Zahl mit der links von ihr vergleichen:

    *  1  2  3  4
    *  2  3  4  4
    *  3  4  4  3
    *  4  4  3  2
    *  4  3  2  1
    

    Also quasi das gleiche Muster minus 1 und gedreht. Man muss also eigentlich nur wissen, dass in der Ecke oben links eine 1 steht, dann kann man einfach diesem Muster folgen. Man muss bloß wissen, dass das Maximum 5 (bzw. 4 für die Horizontale) ist, aber das kennt man ja anhand der Größe der Matrix.

    • Wenn man es drauf anlegt, kann man sich auch eine Rechenvorschrift ausdenken, die einem zu einer Zahl die zugehörigen Koordinaten liefert. Dann könnte man die Zahlen 1-25 durchlaufen und sich zu jeder Zahl die Koordinaten ausrechnen und dann die Zahl an diese Stelle schreiben. Diese Methode gefällt mir nicht so sehr, da sie quasi voraussetzt, dass man eine der anderen Methoden umdreht, um sich die Rechenvorschrift auszudenken. Ist aber trotzdem eine Methode, die ich nicht unerwähnt lassen wollte.


  • Ich habe mich mal an die Aufgabe gemacht und es nicht schön gelöst, aber immerhin eine Lösung. Das kann man natürlich noch schöner in Funktionen kapseln usw.

    Mein Programm:

    #include <iostream>
    
    using namespace std;
    
    const int dim = 5;
    int m[dim][dim];
    
    int main() {
    
    	int v = 1;
    	// obere linke Ecke
    	m[0][0] = v++;
    
    	// bis zur Diagonalen
    	for(int i = 2; i <= dim; ++i) {
    		int a = 0;
    		for(int k = 0; k < i; ++k){
    			int y = a;
    			int x = i - a++ -1;
    			m[y][x] = v++;
    		}
    	}
    
    	// von der Diagonalen bis zur unteren rechten Ecke
    	for(int i = dim - 1; i >= 2; --i) {
    		int a = 0;
    		for(int k = 0; k < i; ++k){
    			int y = a + dim - i;
    			int x = dim - 1 - a++;
    			m[y][x] = v++;
    		}
    	}
    
    	// untere rechte Ecke
    	m[dim-1][dim-1] = v;
    
    	// Ausgabe
    	for (int y = 0; y < dim; ++y) {
    		for (int x = 0; x < dim; ++x) {
    			cout << m[y][x] << "\t";
    		}
    		cout << endl;
    	}
    }
    

    Ausgabe:

    1	2	4	7	11	
    3	5	8	12	16	
    6	9	13	17	20	
    10	14	18	21	23	
    15	19	22	24	25
    

    EDIT: Da sind noch Fehler drin, habe jetzt aber keine Zeit mehr zum beheben.
    EDIT2: Ich habe den Code nochmals überarbeitet und er ist jetzt auch ein wenig übersichtlicher. Das l wurde gegen ein a ausgetauscht, da man ein l und eine 1 hier optisch nur sehr schwer unterscheiden kann.



  • Erstmal ein Dickes Danke für soviel Text und Erklärung von dir. Der Platz im Foren Himmel ist dir auf alle Fälle sicher., und in Zukunft weiß ich auch welches Forum ich denke mal öfter benutzten werde 🙂

    SeppJ schrieb:

    Hier geht leider sehr viel schief und zwar schon im allerersten Schritt, wodurch dann der ganze Rest automatisch auch mit umfällt. Wie du da dein Array definiert hast, ist das kein C++. Du nutzt da ein spezielles Feature der Sprache C (sogenannte VLAs), die von einem gewissen C++-Compiler als Zusatzfeature für C++ unterstützt werden (oder eher: Man hat dieses Feature im C++-Modus des Compilers nicht absichtlich abgeschaltet). Viele C++-Compiler unterstützen dies nicht. Dein Code wird mit diesen Compilern nicht übersetzbar sein. Außerdem lernst du nicht, wie es in C++ richtig geht (C++ hat nämlich viel bessere Mechanismen).

    In C und C++ muss die Größe eines Arrays zur Compilezeit fest stehen, dass heißt, die Größenangabe muss ein Literal (z.B. int foo[5]; ) oder eine Konstante (z.B. const int size = 5; int foo[size]; . Wobei dies nur in C++ funktioniert, in C gelten Variablen trotz const als variabel) sein.

    In C gibt es seit dem Standard von 1999 (den aber einer der größten Compiler bis heute nicht umsetzt) auch die VLAs, mit denen man auch Variablen zur Größenangabe nutzen kann und dann eben erst zur Laufzeit bestimmt wird, wie groß das Array genau ist. Das Feature ist ein wenig problematisch, aus Gründen, die hier nicht wichtig sind und in der Folge, würde man ein VLA auch ganz anders einsetzen als hier. Aber da dies nicht das C-Forum ist, gehe ich da mal nicht weiter drauf ein, sondern sage nur, dass es so nicht geht.

    ALso mein gnu compiler unterstützt das anscheinend denn der fertige code siehe unten läuft ja ;-).Hab diese VLAs nicht mit absicht benutzt dachte nur warum soll das nicht gehen 😉 aber wenn ich das richtig verstanden habe dann muss der compiler quasi vorher wissen wieviel Speicherplatz er einem Feld zuweist?!?

    Aber das Problem ließe sich ja dann beheben wenn ich einfach eine maximale größe von 100x100 (laut aufgabenstellung) bestimme und die wirkliche größe z.B. 5 dann einfach per x übergebe oder?

    In C++ gibt es sehr viele Wege, ähnliches zu erreichen. Manche davon deutlich besser. Viele auch deutlich umständlicher, besonders die, die sich nur auf die allereinfachsten Sprachmittel beschränken. Ich habe den Eindruck, letzteres ist bei dir der Fall, oder? Die Nonplusultralösung würde alle dieser Stichworte benötigen: Klassen, std::vector, Templates, Operatorüberladung. Irgendwas davon schon einmal gehört? Zur Not kann man sich nämlich auch auf std::vector beschränken, aber wenn das alles ist, was man nutzen kann, dann wird es, wie erwähnt, ziemlich umständlich. Wohingegen die Lösung, bei der man aus dem Vollen schöpfen kann, sehr einfach zu benutzen wäre und dich, wenn man es ein einziges Mal gut macht, sogar für alle Zeit begleiten kann.

    Falls man nicht einmal std::vector zur Verfügung haben sollte, kann man sich diesen eventuell nachprogrammieren, wofür man aber wieder mindestens die gleichen Sprachfeatures bräuchte, die oben erwähnt wurden.

    in unserer Vorlesung kommenen Klassen als nächstes dran also muss es ja möglich sein die Aufgabe zu lösen ohne die Hilfe von Vectoren o.ä.

    Falls man weder std::vector hat, noch diesen nachprogrammieren kann, dann muss man darauf verzichten, die Größe der Matrix erst zur Laufzeit festzulegen. Dann muss man eben fest

    int matrix[10][10];
    

    schreiben. Dann funktioniert auch deine zweite Variante, die du im Netz gefunden hast*. Die erste Variante, die du dir selber ausgedacht hast, ist hingegen schlicht Unsinn. In C++ hat man auch die bessere Möglichkeit, statt dem rohen Array ein std::array zu nutzen. Technisch ist das das gleiche, aber anfängerfreundlicher in der Benutzung, da es die bösen Überraschungen vermeidet, die fast jeder Anfänger+ in C mit Arrays im Zusammenspiel mit Funktionen hat. Das wäre dann, da du ein std::array von std::arrays möchtest, ein geschachtelter Datentyp:

    std::array<std::array<int, 10>, 10> matrix;
    

    Ein typedef bietet sich an, wenn man das so benutzen möchte. Das kannst du dann auch ganz direkt an eine Funktion übergeben, so wie du es kennst, ohne die komischen Sonderverrenkungen für rohe Arrays. Das ist sogar einer der Hauptgedanken, warum es std::array gibt.

    💡 Falls du gerade nur Bahnhof verstehst, wäre es vielleicht eine gute Idee, darauf zu verzichten, die Matrix in einer Funktion zu füllen und stattdessen die Füllung ins Hauptprogramm zu schreiben. 💡

    Ja aber laut unserem Lehrer ist das nicht im Sinne der "strukturierten Programmierung wenn die Main funktion etwas anderes als die Verwaltung übernimmt.

    *: Falls es nicht klar ist: Suche im Netz und Zusammenkopieren von Code ist nicht Programmieren. Code ist Logik pur; du musst von jedem Zeichen in deinem Programm genau wissen, wo und warum du es setzt! Es ist natürlich nicht verkehrt, im Netz zu suchen, wenn man Hilfe nötig hat, aber es ist wichtig, dass du die Hilfe auch verstehst und nicht nur kopierst. Gehe ich recht in der Annahme, dass du die VLAs auch irgendwo kopiert hast?
    Es ist irgendwie komisch, dass du diese Übungsaufgabe bekommen hast, obwohl anscheinend nicht die nötigen Sprachmittel durch genommen wurden. Das wirft kein gutes Licht auf den Lehrer bzw. das Lehrbuch. Leider ist das aber auch nichts neues, gerade im deutschsprachigen Raum gibt es sehr viel, sehr schlechtes Lehrmaterial zu C++. Meistens entweder von ahnungslosen Anfängern selber geschrieben oder von Leuten, die von 40 Jahren mal Fortran gelernt haben und nun denken, sie können C++, wenn sie nur print durch cout ersetzen. Wie lernst du C++?

    +: Zumindest die, mit schlechten Lehrbüchern/Lehrern. Ich habe den Eindruck, du gehörst dazu. Siehe meine Signatur für Empfehlungen zu guten (C++-)Büchern.

    Der unten genannte Code den hab ich selbst geschrieben nicht ein bisschen ist davon aus dem Internet ich habe ja auch eher nach einem Sprungbrett gesucht da ich gestern komplett auf dem Schlauch stand nachdem ich es 20 mal probiert habe mit Hilfe der Formeln die du auch unten gennant hattest also wo man quasi Zeile für Zeile eine Iteration einbaut aber das hat bei mir nicht auf einer x*x matrix funktioniert sondern nur auf speziellen 😞

    Die VLA's hab ich nicht irgendwo übernommen sondern bin einfach davon ausgegangen das wenn man eine matrix[19][19] initieren kann das dass dann auch mit [x][y] geht 😢 dem ist ja aber anscheinend nicht so.
    Im Moment ist das Problem was ich habe das das Buch was ich neben der Vorlesung lese ("object-Oriented Programming in C++" Nicolai M. Josuttis) ganz anders Strukturiert ist als die Vorlesung selber 😞

    http://ideone.com/DhYm0J

    #include <iostream>
    
    int main(){
    	int x=10;
    	int y=10;
    	int matrix[x][y];
    	for (int i = 0; i<x; i++) {
    		for (int j =0; j<y; j++){ // wollte nur sichergehen dass kein Ergebnis durch unbestimmte Speicherplätze gefälscht wird
    			matrix[i][j]=0;
    			}
    		}
    
    	int cntx,cnty; // 2 Hilfsvariablen zum hoch bzw. runterzählen
    	int i=1;
    	cntx=0;
    	cnty=0;
    	for(int max=0;max<x;max++){ // da die erste Zahl [0][0] die 2=[0][1] 3.=[01][0]... [0->max][max->0] 
    		cnty=max; // sozusagen y=[max->0] da muss ich ja am anfang auf max sezten
    		cntx=0;
    		while(cnty>=0){
    		matrix[cntx][cnty]=i;
    		i++;
    		cntx++;
    		cnty--;
    		}
    	}
    	//unterer Teil
    	i=x*x;
    	cntx=x-1;
    	cnty=x-1;
    	for(int min=x-1;min>0;min--){ // da die erste Zahl [0][0] die 2=[0][1] 3.=[01][0]... [0->max][max->0] 
    		cnty=min; // sozusagen y=[max->0] da muss ich ja am anfang auf max sezten
    		cntx=x-1;
    		while(cnty<=x-1){
    		matrix[cntx][cnty]=i;
    		i--;
    		cntx--;
    		cnty++;
    		}
    	}
    
    	//Ausgabe
    	for (int i = 0; i <x; i++) {
    		for (int j =0; j<y; j++){
    			std::cout<<matrix[i][j]<<"\t";
    			}
    			std::cout<<"\n";
    			}
    }
    

  • Mod

    Mvstylez schrieb:

    Aber das Problem ließe sich ja dann beheben wenn ich einfach eine maximale größe von 100x100 (laut aufgabenstellung) bestimme und die wirkliche größe z.B. 5 dann einfach per x übergebe oder?

    Das mit der Maximalgröße ist die nötige Einschränkung, mit der das Ganze auch mit einfachen Mitteln lösbar wird. Die richtige Vorgehensweise hast du auch schon selber gefunden.



  • Hier noch eine andere Lösung.

    #include <iostream>
    
    using namespace std;
    
    const int dim = 5;
    int m[dim][dim];
    
    int main() {
    
    	// Berechnung
    	int v = 1;
    	for (int i = 0; i < 2 * dim - 1; ++i) {
        	int a = 0;
        	if (i >= dim) a = i - dim + 1;
    
        	for (int k = a; k <= i - a; ++k)
            	m[k][i - k] = v++;
    	}
    
    	// Ausgabe
    	for (int y = 0; y < 5; ++y) {
    		for (int x = 0; x < 5; ++x) {
    			cout << m[y][x] << "\t";
    		}
    		cout << endl;
    	}
    }
    

    Ausgabe:

    1	2	4	7	11	
    3	5	8	12	16	
    6	9	13	17	20	
    10	14	18	21	23	
    15	19	22	24	25
    


  • auch dir danke für deinen Beitrag aber wie gesagt suche ich nicht nach der Lösung sondern nach dem weg dahin 😉
    und die Berechnung habe ich ja jetzt schon jetzt geht es nur um die Auslagerung der Ausgabe in eine Eigene Funktion.
    habe das jetzt gelöst hatte noch einen kleinen denkfehler ich dachte ich muss um die matrix zu übergeben bsp: ausgabe(matrix[maxsize][maxsize],x); hinschreiben
    und da kam dann immer ein Fehler, aber einfach nur matrix reinzuschreiben erschien mir zu einfach 🙂

    #include <iostream>
    
    int eingabe(){
    	int x;
    	std::cout<<"Bitte geben sie eine Zahl von 1-100 ein: ";
    	std::cin>>x;
    	std::cout<<std::endl;
    	return x;
    }
    
    const int maxsize=100;
    int matrix[maxsize][maxsize];
    
    void ausgabe(int a[][maxsize],int x){
    	for (int i = 0; i <x; i++) {
    		for (int j =0; j<x; j++){
    			std::cout<<matrix[i][j]<<"\t";
    			}
    			std::cout<<"\n";
    			}
    }
    
    int main(){
    	int x;
    	x = eingabe();
    		for (int i = 0; i<x; i++) {
    		for (int j =0; j<x; j++){ // wollte nur sichergehen dass kein Ergebnis durch unbestimmte Speicherplätze gefälscht wird
    			matrix[i][j]=0;
    			}
    		}
    
    	int cntx,cnty; // 2 Hilfsvariablen zum hoch bzw. runterzählen
    	int i=1;
    	cntx=0;
    	cnty=0;
    	for(int max=0;max<x;max++){ // da die erste Zahl [0][0] die 2=[0][1] 3.=[01][0]... [0->max][max->0] 
    		cnty=max; // sozusagen y=[max->0] da muss ich ja am anfang auf max sezten
    		cntx=0;
    		while(cnty>=0){
    		matrix[cntx][cnty]=i;
    		i++;
    		cntx++;
    		cnty--;
    		}
    	}
    	//unterer Teil
    	i=x*x;
    	cntx=x-1;
    	cnty=x-1;
    	for(int min=x-1;min>0;min--){ 
    		cnty=min;
    		cntx=x-1;
    		while(cnty<=x-1){
    		matrix[cntx][cnty]=i;
    		i--;
    		cntx--;
    		cnty++;
    		}
    	}
    	ausgabe(matrix,x);
    
    }
    

    Ich habe bestimmt nachher noch ein paar andere fragen, da dieses nur das Basisprogramm war jetzt geht es darum
    1.Die Matrix an der Nebendiagonale zu Spiegeln
    2.die Matrix im Uhrzeigersinn zu drehen .
    3.Die Summe der Haupt und Neben Diagonalen ausrechnen
    4.Die Summe des Dreiecks über/unter/link/rechts der beiden Diagonalen ohne die diagonalen zu berechnen.

    zu 1. Da kann man doch einfach 2mal die Funktion aus 2. aufrufen oder sehe ich das falsch?
    zu 2. Ich würde da eine neue Matrix machen in der ich die Spalten zwischenzeitlich einspeicher? würde am Ende auch nur ein eindimensionales feld reichen?!? nach kurzem nachdenken sollten ja auch einfach 1 Hilfsvariable herhalten in die ich die neuzutauschende Zahl speicher sodass ich den Platz nicht überschreibe
    3. sollte relativ einfach sein einfach

    if (x==y){sum += matrix[x][y]}
    

    für die Haupt und für die Nebendiagonale

    for (i=x...;i--){for(k=0;...k++){sum+=matrix[i][k]}
    

    hoffe das ist zu verstehen poste nachher das ergebnis wenn es so geklappt hat
    4. überleg ich mir dann 😉

    Ich denke das ist okay wenn ich da in diesem thread weiterschreibe weil dann wissen ja alle schonmal wie die Basis funktioniert und das ich keine Ahnung der Materie habe bevor ich einen neuen aufmache;-)



  • #include <iostream>
    
    const int maxsize=100;
    int matrix[maxsize][maxsize];
    int b[maxsize][maxsize];
    
    int menu(){
    	int m=9;
    	while(m>4||m<0){
    	std::cout<<"\n\n1. Neue x*x Matrix erstellen\n";
    	std::cout<<"2. Spiegeln der Matrix an der Nebendiagonalen\n";
    	std::cout<<"3. Rotieren der Matrix im Uhrzeigersinn\n";
    	std::cout<<"4. Summen anzeigen\n";
    	std::cout<<"Beendung des Programmes mit der Eingabe der Zahl 0\n";
    	std::cin>>m;
    	if(m>4||m<0){
    		std::cout<<"\nUngültige Eingabe! Bitte versuchen Sie es erneut!\n";
    	} else {return m;
    		}
    	}
    	return m;
    }
    
    int eingabe(){
    	int x=0;
    	while (x<=0 || x>100){
    	std::cout<<"\nBitte geben Sie die Anzahl von Spalten/Zeilen mit einer Zahl von 1 bis 100 ein: ";
    	std::cin>>x;
    	std::cout<<std::endl;
    	if (x<=0 || x>100){
    		std::cout<<"Bitte geben Sie eine gültige Zahl ein\n";
    		}
    	}
    	return x;
    }
    
    void ausgabe(int a[][maxsize],int x){
    	std::cout<<"\n\n"<<std::endl;
    	for (int i = 0; i <x; i++) {
    		for (int j =0; j<x; j++){
    			std::cout<<a[i][j]<<"\t";
    			}
    			std::cout<<"\n";
    			}
    }
    
    void spiegeln(int x){
    	int cntx,cnty;
    			int i=1;
    			cntx=x-1;
    			cnty=x-1;
    			for(int max=x-1;max>=0;max--){  
    				cnty=x-1; 
    				cntx=max;
    				while(cntx<x){
    				matrix[cntx][cnty]=i;
    				i++;
    				cntx++;
    				cnty--;
    				}
    			}
    			i=x*x;
    			cntx=0;
    			cnty=0;
    			for(int max=0;max<x;max++){
    				cnty=max;
    				cntx=0;
    				while(cnty>=0){
    				matrix[cnty][cntx]=i;
    				i--;
    				cntx++;
    				cnty--;
    				}
    			}
    }
    
    void rotate(int a[][maxsize],int x){
    	for(int i=0;i<x;i++){
    		for(int k=0;k<x;k++){
    			b[i][k]=a[i][k];
    		}
    	}
    	int y=x;
    	for(int i=0;i<x;i++){
    		y--;
    		for(int k=0;k<x;k++){
    			a[k][y]=b[i][k];
    		}
    	}
    }
    void summen(int a[][maxsize],int x){
    	int haupt=0;
    	int neben=0;
    	int nord=0;
    	int ost=0;
    	int sued=0;
    	int west=0;
    	int i=0;
    	int k=x-1;
    	while(i<x){
    		haupt+=a[i][i];
    		i++;
    	}
    	i=0;
    
    	while(i<x){
    		neben+=a[i][k];
    		i++;
    		k--;
    	}
    	k=0;
    	int anfang;
    	int ende;
    	for(int i=0;i<x/2;i++){
    		anfang =i+1;
    		ende=x-i-1;
    		for(int k=anfang;k<ende;k++){
    			nord+=a[i][k];
    		}
    	}
    	//west
    	rotate(matrix,x);
    		k=0;
    	for(int i=0;i<x/2;i++){
    		anfang =i+1;
    		ende=x-i-1;
    		for(int k=anfang;k<ende;k++){
    			west+=a[i][k];
    		}
    	}
    	rotate(matrix,x);
    	rotate(matrix,x);
    	rotate(matrix,x);
    	//Süd
    	rotate(matrix,x);
    	rotate(matrix,x);
    		k=0;
    	for(int i=0;i<x/2;i++){
    		anfang =i+1;
    		ende=x-i-1;
    		for(int k=anfang;k<ende;k++){
    			sued+=a[i][k];
    		}
    	}
    	rotate(matrix,x);
    	rotate(matrix,x);
    	//ost
    	rotate(matrix,x);
    	rotate(matrix,x);
    	rotate(matrix,x);
    		k=0;
    	for(int i=0;i<x/2;i++){
    		anfang =i+1;
    		ende=x-i-1;
    		for(int k=anfang;k<ende;k++){
    			ost+=a[i][k];
    		}
    	}
    	rotate(matrix,x);
    
    	//Ausgabe Summen
    	std::cout<<"\nDie Summe der Hauptdiagonalen beträgt: "<<haupt<<std::endl;
    	std::cout<<"Die Summe der Nebendiagonalen beträgt: "<<neben<<std::endl;
    	std::cout<<"Die Summe des Norddreiecks beträgt   : "<<nord<<std::endl;
    	std::cout<<"Die Summe des Ostdreiecks beträgt   : "<<ost<<std::endl;
    	std::cout<<"Die Summe des Sueddreiecks beträgt   : "<<sued<<std::endl;
    	std::cout<<"Die Summe des Westdreiecks beträgt   : "<<west<<std::endl;
    
    }
    
    void makem(int x){
    	for (int i = 0; i<x; i++) {
    	for (int j =0; j<x; j++){ 
    			matrix[i][j]=0;
    			}
    	}
    	int cntx,cnty;
    	int i=1;
    	cntx=0;
    	cnty=0;
    	for(int max=0;max<x;max++){ 
    		cnty=max;
    		cntx=0;
    		while(cnty>=0){
    		matrix[cntx][cnty]=i;
    		i++;
    		cntx++;
    		cnty--;
    		}
    	}
    	//unterer Teil
    	i=x*x;
    	cntx=x-1;
    	cnty=x-1;
    	for(int min=x-1;min>0;min--){ 
    		cnty=min;
    		cntx=x-1;
    		while(cnty<=x-1){
    		matrix[cntx][cnty]=i;
    		i--;
    		cntx--;
    		cnty++;
    		}
    	}
    }		
    
    int main(){
    	std::cout<<"\n\tHausaufgabe Nr. 4 Felder\n\n";
    	std::cout<<"Bitte erstellen Sie zuerst eine Matrix\n";
    	int x=eingabe();
    	makem(x);
    	ausgabe(matrix,x);
    	int cnt=0;
    	int m=menu();
    	if(m==2)cnt++;
    	while(true){
    		if (m==0) return 0;
    		if (m==1){ 
    			x=eingabe();
    			makem(x);
    			ausgabe(matrix,x);
    		}	
    		if (m==2){
    			spiegeln(x);
    			ausgabe(matrix,x);
    
    		}
    		if (m==3){
    			rotate(matrix,x);
    			ausgabe(matrix,x); 
    		 }
    		if (m==4){
    			ausgabe(matrix,x);
    			summen(matrix,x);			
    		}
    	m=menu();
    	if (m==2 && cnt==1){
    		std::cout<<"\n\nBitte erstellen Sie zuerst eine neue Matrix\n";
    		m=1;
    	}else { if(m==1) cnt=0;
    	}
    	}	
    
    }
    

    soo hier das fertige Produkt bei Anregungen oder Verbesserungsvorschlägen bin ich gerne bereit zuzuhören 😉
    ja ich bin mir bewusst das es keine wirkliche Spiegelung ist...


  • Mod

    Kommt dir die summen-Funktion nicht irgendwie unnötig umständlich oder ungeschickt vor? Würdest du im Kopf/auf Papier auch so vorgehen?



  • Du meinst weil ich die Matrix immer wieder auf die Ursprungssituation zurück drehe? Das hab ich nur gemacht weil ich am Anfang noch nicht wusste ob ich das alles auf extra Funktionen auslagern werde(was ich am ende nicht gemacht habe). Könnte ich quasi auch nord ausrechnen->drehen->westausrechnen->drehen->süd ausrechnen-> drehen-> ost-> zum ursprung zurückrechnen


  • Mod

    Mvstylez schrieb:

    Du meinst weil ich die Matrix immer wieder auf die Ursprungssituation zurück drehe?

    Auch. Das ist aber im Prinzip nur ein Symptom, weil du die Matrix überhaupt drehst. Würdest du im echten Leben bei der Aufgabe wirklich jedes Mal die Matrix drehen (noch dazu in mehreren Einzelschritten?), weil du nur weißt, wie du eines der Dreiecke aufsummierst und nicht fähig bist, dies für die anderen Dreiecke zu tun?



  • Achso nein die Berechnungen unterscheiden sich ja nicht so großartig aber wenn ich die Berechnung für ein Dreieck habe und die Berechnung zum rotieren muss ich mir ja kein Kopf machen wie ich die anderen berechne;-) oder gibt es davon Nachteile?


  • Mod

    Mvstylez schrieb:

    Achso nein die Berechnungen unterscheiden sich ja nicht so großartig aber wenn ich die Berechnung für ein Dreieck habe und die Berechnung zum rotieren muss ich mir ja kein Kopf machen wie ich die anderen berechne;-) oder gibt es davon Nachteile?

    Während das einerseits ein effizienter Einsatz der vorhandenen Mittel ist, tut es andererseits dem Numeriker in mir eben weh, so viel verschwendete Rechenzeit zu sehen.



  • haha na ich bin nicht das größte Mathe Genie also wenn ich etwas irgendwie Umgehen kann dann mache ich das auch 😉
    aber ich werde in Zukunft versuchen darauf zu achten das es dir nicht kalt den rücken runter läuft wenn du mir mal wieder hilfst 😉



  • @Mvstylez: Du hast deine Aufgabe erfüllt und damit lass es gut sein. Wenn du immer und überall das Beste machen willst, wirst du nie fertig und hängst an unwichtigen Sachen fest. Zu deiner Aufgabe gehört bestimmt nicht die Lösung hoch zu optimieren, so dass auch irgendein Numerik-Freak damit einverstanden ist.

    Wenn ich erst anfange Programme zu schreiben wenn ich jeden Kniff von C++ kenne und auch noch optimiere kann, dann wäre so gut wie nie ein Programm bei mir fertig geworden. Arbeite nach den Anforderungen und gut ist.



  • Also im Sinne von SeppJ hätte ich da noch einen Vorschlag.

    Wie mache ich es per Hand?

    Eigentlich laufe ich die diagonalen Streifen ab und hab nen globalen Hochzähler, den ich von 1 bis 25 laufen lasse.

    Tja, eigentlich...

    Ich sags mal andersrum (andersrum ist meistens dumm!).
    Ich lasse die Zahl von 1 bis 25 laufen und laufe dabei die Streifen ab.

    Das mache ich mal.

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main(){
    	int dim=5;
    	int arr[dim][dim];
    
    	int y=0,x=0;//Das ist die Position, wo ich reinschreibe
    	for(int i=1;i<=dim*dim;++i){
    		arr[y][x]=i;//genau, da schreibe ich rein
    		if(x==0){//wenn ich am linken rand bin, setze ich oben an eins weiter rechts
    			x=y+1;
    			y=0;
    		}
    		else{//ansonsten gehe ich schräg nach linksunten
    			--x;
    			++y;
    		}
    	}
    
    	for(int y=0;y<dim;++y){
    		for(int x=0;x<dim;++x){
    			cout<<setw(3)<<arr[y][x]<<' ';
    		}
    		cout<<'\n';
    	}
    }
    
    1   2   4   7  11 
     16  22   8  12  17 
     23   9  13  18  24 
     10  14  19  25 32513 
     15  20   6   0 6295640
    

    Jo, einige Zahlen passen schon.

    Pro Zahl zwei if, das ätzt ein wenig (assembler-ifs, eins in der Schleifenbedingung und eins im Körper).

    Also das linke obere Dreieck geht so per Hand. Ab dann wirds gruselig. Also mehr if und else machen, damit alles erkannt wird, was ich als Mensch so einfach sehe, wo es weiter geht. Nur kann ich echt nicht fassen, was ich so mit meinen Augen klar erkenne.

    Also mal einschränken auf die erste Hälfte bis einschließlich zur Mitte:

    for(int i=1;i<=(dim*dim+1)/2;++i){
    
    1   2   4   7  11 
      3   5   8  12 32747 
      6   9  13 32747 651264496 
     10 653906272 32747 653906272 32747 
    653906560 32747 651204056 32747   0
    

    Passt! Also bis in die Mitte.

    Da fällt mir ein alter Programmiertrick ein. Von hinten ist hier wie von vorne.

    arr[y][x]=i;//genau, da schreibe ich rein
    		arr[dim-1-y][dim-1-x]=dim*dim+1-i;//und von hinten auch
    

    Passt.

    Zusammen:

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main(){
    	int dim=5;
    	int arr[dim][dim];
    
    	int y=0,x=0;//Das ist die Position, wo ich reinschreibe
    	for(int i=1;i<=(dim*dim+1)/2;++i){
    		arr[y][x]=i;//genau, da schreibe ich rein
    		arr[dim-1-y][dim-1-x]=dim*dim+1-i;//und von hinten auch
    		if(x==0){//wenn ich am linken rand bin, setze ich oben an eins weiter rechts
    			x=y+1;
    			y=0;
    		}
    		else{//ansonsten gehe ich schräg nach linksunten
    			--x;
    			++y;
    		}
    	}
    
    	for(int y=0;y<dim;++y){
    		for(int x=0;x<dim;++x){
    			cout<<setw(3)<<arr[y][x]<<' ';
    		}
    		cout<<'\n';
    	}
    }
    

    Ok, der Code ist einigermaßen schlank. Auch einigermaßen schnell. Und nur zur Not verständlich, weil ich ihn in kleinen Etappen entwickelt habe. Eigentlich stinkt er.

    Wie würde es aussehen, wenn ich planvoll das erste Dreieck ausmalen würde?

    int zahl=1;
    	for(int startX=0;startX<dim-1;++startX){
    		int x=startX;
    		int y=0;
    		while(x>=0){
    			arr[y][x]=zahl;
    			++zahl;
    			--x,++y;
    		}
    	}
    

    Passt.

    Dann wäre das Prog zusammen:

    //male Dreick oben links
    	//male Diagonale
    	//male Dreieck unten rechts
    

    Und es wäre befreit von der ekligen Zeile

    arr[dim-1-y][dim-1-x]=dim*dim+1-i;
    

    , die man zugegeben nicht klar lesen kann.
    Und das Prog hätte pro Zahl nur um ein teures if, würde stark in die Richtung gehen, optimal schnell zu sein. Und es wäre "langweilig", was das allerallergrößte Lob an Code ist, der ansonsten hinreichend schlank und effizient ist.

    Man solls erstmal probieren, wie man es als Mensch macht. Andersrum ist meistens dumm.

    Fertiger Code:

    int zahl=1;
    	for(int startX=0;startX<dim;++startX){
    		int x=startX;
    		int y=0;
    		while(x>=0){
    			arr[y][x]=zahl;
    			++zahl;
    			--x,++y;
    		}
    	}
    	for(int startY=1;startY<dim;++startY){
    		int y=startY;
    		int x=dim-1;
    		while(y<dim){
    			arr[y][x]=zahl;
    			++zahl;
    			--x,++y;
    		}
    	}
    

    AntiOptimierer schrieb:

    @Mvstylez: Du hast deine Aufgabe erfüllt und damit lass es gut sein. Wenn du immer und überall das Beste machen willst, wirst du nie fertig und hängst an unwichtigen Sachen fest. Zu deiner Aufgabe gehört bestimmt nicht die Lösung hoch zu optimieren, so dass auch irgendein Numerik-Freak damit einverstanden ist.

    Ja und nein. Man wird nicht extrem gut, wenn man nicht ruhelos nach Verbesserungen sucht, sondern man bleibt nur sehr gut. Solange man an der Hochschule ist hat man noch Zeit für sowas. Wenns einem Spaß macht, warum nicht? Und kann ja sein, daß man damit dem Prof auffällt und er einen für gute externe Diplomarbeiten empfiehlt und man die ersten beiden Karrieresprünge übergeht aus Versehen.



  • AntiOptimierer schrieb:

    @Mvstylez: Du hast deine Aufgabe erfüllt und damit lass es gut sein. Wenn du immer und überall das Beste machen willst, wirst du nie fertig und hängst an unwichtigen Sachen fest. Zu deiner Aufgabe gehört bestimmt nicht die Lösung hoch zu optimieren, so dass auch irgendein Numerik-Freak damit einverstanden ist.

    Wenn ich erst anfange Programme zu schreiben wenn ich jeden Kniff von C++ kenne und auch noch optimiere kann, dann wäre so gut wie nie ein Programm bei mir fertig geworden. Arbeite nach den Anforderungen und gut ist.

    Ja diese "Das Pferd springt nur so hoch wie es muss" Philosophie ergibt ja Sinn wenn es mir darum geht nur Aufgabe zu bestehen und klar ist meine erste Priorität dass das Programm erstmal macht was es machen soll aber wenn ich das geschafft habe kann man ja nach alternativen vlt. Besseren schnelleren Lösungen suchen damit man sich Methoden für die Zukunft merken kann sonst lernt man ja nichts dazu und in 5 Jahren mache ich es immer noch so umständlich wie am Anfang 🙂


Anmelden zum Antworten