rekursiver Aufbau einer Matrix



  • bomberking schrieb:

    Das Problem ist, daß ich ja irgendwie einen ganzen Block von Array-Komponenten übergeben müsste.

    Du meinst die ganze Matrix - oder?

    bomberking schrieb:

    Mein großes Problem ist auch, daß ich Zeiger wie die Pest hasse ;), wenn ihr also Tips habt, wie man das Ganze recht nett mit Arrays lösen kann, wäre ich Euch sehr verbunden 🙂

    kein Problem, beim richtigen Einsatz von C++ kommst Du ganz ohne Zeiger aus!

    Bau' Dir zunächst eine ganz einfache Matrix-Klasse:

    // -- Matrix.h
    #include <algorithm>    // std::copy
    #include <cassert>
    #include <cstddef>      // std::size_t
    #include <iostream>
    #include <iomanip>
    #include <vector>
    
    class Matrix
    {
    public:
        typedef std::size_t size_type;
        typedef int value_type;
    
        Matrix()
            : m_nSpalten( 0 )
            , m_data()
        {}
    
        Matrix( size_type nZeilen, size_type nSpalten, const value_type& x = value_type() )
            : m_nSpalten( nSpalten )
            , m_data( nZeilen * nSpalten, x )
        {}
    
        // --   Element-Zugriff
        value_type* operator[]( size_type iZeile )
        {
            return &m_data[ iZeile * m_nSpalten ];
        }
    
        size_type Zeilen() const { return m_data.empty()? 0: m_data.size() / m_nSpalten; }
        size_type Spalten() const { return m_nSpalten; }
    
        // --   Ausgabe
        friend std::ostream& operator<<( std::ostream& out, const Matrix& mx );
    private:
        size_type m_nSpalten;
        std::vector< value_type > m_data;
    };
    

    Durch die Verwendung des std::vector's brauchst Du Dir keine Gedanken mehr um das Kopieren der Matrix, um Speicher-Allokierung und Zeiger-Wirrwar machen. Das nimmt Dir alles der std::vector ab.

    Um Dein obiges Problem zu lösen, benötigst Du noch eine Methode 'insert', mit der Du eine UnterMatrix hinzufügen bzw. überschreiben kannst.

    void insert( size_type iZeile, size_type iSpalte, const Matrix& b )
        {
            assert( iZeile + b.Zeilen() <= Zeilen() );
            assert( iSpalte + b.Spalten() <= Spalten() );
            for( std::vector< value_type >::const_iterator src = b.m_data.begin(); src != b.m_data.end()
                ; src += b.Spalten(), ++iZeile )
            {
                // eine Zeile kopieren
                std::copy( src, src + b.Spalten(), m_data.begin() + iZeile * m_nSpalten + iSpalte );  
            }
        }
    

    Der Rest wird jetzt recht einfach

    // --   main.cpp
    #include "Matrix.h"
    #include <iostream>
    #include <iomanip>
    
    // --  Der rekursive Algorithmus
    Matrix makeNextMatrix( const Matrix& mx )
    {
        Matrix ret( mx.Zeilen()*2, mx.Spalten()*2, 0 );
        ret.insert( 0, 0, mx );
        ret.insert( 0, mx.Spalten(), mx );
        ret.insert( mx.Zeilen(), mx.Spalten(), mx );
        return ret;
    }
    
    int main()
    {
        using namespace std;
        Matrix mx( 1, 1, 1 );
        for( int n = 3; n; --n )
            mx = makeNextMatrix( mx );
        // Ergebnis ausgeben
        cout << "Ergebnis-Matrix:\n" << setw(3) << mx << endl;
        return 0;
    }
    

    .. und fertig. Zum Schluß noch die Implementierung der Ausgabe-Funktion

    std::ostream& operator<<( std::ostream& out, const Matrix& mx )
        {
            const std::streamsize w = out.width();
            Matrix::size_type iSp = 0;
            for( std::vector< value_type >::const_iterator i = mx.m_data.begin(); i != mx.m_data.end(); ++i, ++iSp )
            {
                if( iSp == mx.m_nSpalten )
                {
                    out << std::endl;
                    iSp = 0;
                }
                out << std::setw( w ) << *i;
            }
            out << std::endl;
            return out;
        }
    

    Falls Du statt des 'int' einen anderen Element-Typ in der Matrix haben willst, musst Du die Zeile

    typedef int value_type;
    

    entsprechend anpassen.
    Falls Du VC6 verwendest, solltest Du in der Zeile davor das std:: vor size_t weglassen

    typedef std::size_t size_type;
    

    Gruß
    Werner



  • oder direkt berechnen und nix kopieren:

    int at(int x,int y,int size){
    	if(y==0)//edit: ein wenig stärker als if(size==0)
    		return 1;
    	int sh=size/2;
    	if(x<sh)
    		if(y<sh)
    			return at(x,y,sh);
    		else
    			return 0;
    	else
    		if(y<sh)
    			return at(x-sh,y,sh);
    		else
    			return at(x-sh,y-sh,sh);
    }
    
    int size=1<<3;
    		for(int y=0;y<size;++y){
    			for(int x=0;x<size;++x)
    				cout<<at(x,y,size);
    			cout<<'\n';
    		}
    

    edit:
    hab die rekursion weggefrickelt.

    int at(size_t x,size_t y,size_t mask){
    	for(;;){
    		if(x<y)
    			return 0;
    		if(y==0)
    			return 1;
    		x&=mask;
    		y&=mask;
    		mask>>=1;
    	}
    }
    
    int level=3;
    		size_t size=1<<level;
    		size_t mask=~(1<<(level-1));
    		for(size_t y=0;y<size;++y){
    			for(size_t x=0;x<size;++x)
    				cout<<at(x,y,mask);
    			cout<<'\n';
    		}
    

    und noch eine freche optimierung:

    int at(size_t x,size_t y,size_t mask){
    	while(x>y){
    		x&=mask;
    		y&=mask;
    		mask>>=1;
    	}
    	return x==y;
    }
    

    ob das wohl auch ohne schleife geht?



  • Das Ding sieht aus wie ein Sierpinski-Dreieck - gell.

    @bomberking: Brauchst Du die ganze Matrix oder nur die Werte rechts oberhalb der Diagonalen?



  • volkard schrieb:

    hab die rekursion weggefrickelt.

    int at(size_t x,size_t y,size_t mask){
    	for(;;){
    		if(x<y)
    			return 0;
    		if(y==0)
    			return 1;
    		x&=mask;
    		y&=mask;
    		mask>>=1;
    	}
    }
    

    Sehr gut Volkard!
    Bis zur Mitte hatte ich's schon, aber die letzten drei Zeilen fehlten mir noch.

    Gruß
    Werner



  • int at(size_t x,size_t y){
    	return !(y&~x);
    }
    


  • Werner Salomon schrieb:

    Sehr gut Volkard!

    Zu früh gelobt, da fehlten die '~' vor mask..

    int at(size_t x,size_t y,size_t mask){
        for(;;){
            if(x<y)
                return 0;
            if(y==0)
                return 1;
            x&=~mask;  // ~mask
            y&=~mask;
            mask>>=1;
        }
    }
    

    Aber das hier:

    volkard schrieb:

    int at(size_t x,size_t y){
    	return !(y&~x);
    }
    

    ist ja wohl nicht mehr zu toppen 👍

    Gruß
    Werner



  • Werner Salomon schrieb:

    Werner Salomon schrieb:

    Sehr gut Volkard!

    Zu früh gelobt, da fehlten die '~' vor mask..

    das ~ war in der main().



  • Hallo Ihr,
    erstmal vielen Danke für die Hilfe!
    Ist ja echt genial, was ihr so schnell hinbekommen habt.
    Leider ging es etwas zu schnell, da ich mir nun ne Kanne Kaffee kochen musste, damit ich die Nacht überlebe und ich Eure Hilfen verstehe 😉 *uffz*

    Werner Salomon schrieb:

    Das Ding sieht aus wie ein Sierpinski-Dreieck - gell.

    hmm, das ist ne interessante Sichtweise. Ich denke mal, daß ich das die nächsten Tage mal weiterverfolgen werde. Könnte nen ganz neuer Blickwinkel sein 🙂

    Werner Salomon schrieb:

    @bomberking: Brauchst Du die ganze Matrix oder nur die Werte rechts oberhalb der Diagonalen?

    nene, ich brauche leider die ganze Matrix, könnte aber die fehlenden Stellen mit Null ergänzen, da ich die entsprechende Vektorlänge brauche.
    Ich muss nun jeder Zeilenvektor dieser Matrix weiterverbeiten, und das wiederum für alle n.
    Aber die Weiterverarbeitung habe ich wohl schon (nicht optimiert) fertig.
    Ich werde nun mal versuchen die nichtoptimierte Version von euch nach zu voll ziehen und anscließen die Optimierung einbauen und verstehen. Ich denke mal, daß das noch recht heftig wird 😉

    Trotzdem nochmal vielen DANK 🙂



  • bomberking schrieb:

    Ich werde nun mal versuchen die nichtoptimierte Version von euch nach zu voll ziehen und anscließen die Optimierung einbauen und verstehen. Ich denke mal, daß das noch recht heftig wird 😉

    viel glück dabei. aber ich finde dein ansinnen ein wenig übertrieben. ich (als erfinder) habe die optimierte version keineswegs verstanden. irgendwie hat sich irgendwie von fast von alleine alles so ergeben. um das wirklich zu verstehen, würde ich wochen brauchen. aber ich bin auch kein mathematiker, der durchblick sucht, sondern nur ein einfacher informatiker, der lösungen sucht. ich würde vorschlagen, du nimmst die optimierte version und machst an deinen anderen problemen weiter.
    falls du aber so ehrgeizig bist, die optimierte version vestehen zu wollen, dann sei doch bitte so nett, und poste hier eine erklärung, warum das zufällig funktioniert.



  • volkard schrieb:

    bomberking schrieb:

    Ich werde nun mal versuchen die nichtoptimierte Version von euch nach zu voll ziehen und anscließen die Optimierung einbauen und verstehen. Ich denke mal, daß das noch recht heftig wird 😉

    viel glück dabei. aber ich finde dein ansinnen ein wenig übertrieben. ich (als erfinder) habe die optimierte version keineswegs verstanden. irgendwie hat sich irgendwie von fast von alleine alles so ergeben. um das wirklich zu verstehen, würde ich wochen brauchen. aber ich bin auch kein mathematiker, der durchblick sucht, sondern nur ein einfacher informatiker, der lösungen sucht. ich würde vorschlagen, du nimmst die optimierte version und machst an deinen anderen problemen weiter.
    falls du aber so ehrgeizig bist, die optimierte version vestehen zu wollen, dann sei doch bitte so nett, und poste hier eine erklärung, warum das zufällig funktioniert.

    *uups* und ich dachte das wäre recht einfach zu schnackeln 😉
    naja, aber zumindestens die nichtoptimierte Version will ich aber verstehen, da ich in der nächsten Zeit noch einiges an solchen Dingen tun muss.
    Das ist ja jetzt erstmal nur zum Aufwärmen 😉
    ... und zum gewöhnen an C++ und das VS 2005.
    Hast du evtl noch ein paar nette Links, oder Tips zu Büchern, die die ganzen Compiler, ... Einstellungen von VS gut und in deutsch erklären?



  • Moinsen,
    ich habe nun einmal versucht, die Klasse Matrix zu verstehen.
    Dazu habe die sie mit Kommentaren durchgearbeitet. Falls euch bei den Kommentaren falsche Interpretationen meinerseits auffallen, wäre ich Euch sehr dankbar:

    // -- matrix.h
    /*
        Diese Klasse erzeugt quadratische Matrizen, und einige zugehörige Rechoperationen.
      Die Matrix besteht aus einem Vektor vom Typ vector<x> und dieser Vektor hat die Länge spaltenAnzahl*Zeilen
    
    */
    #include <algorithm>    // copy               (Kopiert alle Elemente aus dem Intervall [erstes Argument, zweites Argument] an die Stelle drittes Argument)
                            // ________________________________________________________________________________________________________
    #include <cassert>      // assert            (prüft eine Bedingung, bei nicht Erfüllen bricht es das Programm ab)
                            // ________________________________________________________________________________________________________
    #include <cstddef>      // size_t            (ist ein vorzeichenloser Ganzzahltyp für size())
                            // ________________________________________________________________________________________________________
    #include <iostream>     // cout    << w      (gibt den übergebenen Wert w an die Standardausgabe)
                            //                                die Rückgabe ist vom Typ ostream
    #include <iomanip>      // setw()            (gibt an, wieviele Stellen der auszugebene Wert haben soll)
                            // ________________________________________________________________________________________________________
    #include <vector>       // vector<x>         (Der DatentypVector bstehend aus Elementen des einfachen Datentyps x)
                            // const_iterator    (ist ein Zähler der  arrayweise durch alle Mitglieder eines Vektors läuft)
                            // size()            (die Länge des aktuellen Vektors)
                            // empty()           (TRUE für leeren Vektor, FALSE sonst )
                            // operator[x]       (gibt die Referenz auf das Vektorobjekt an der Stelle x zurück, wobei x vom Typ size_t sein sollte)
                            // begin()           (gibt den Zählerwert des ersten Elements des Array als iterator wieder)
                            // end()             (gibt den Zählerwert des letzten Elements des Array als iterator wieder)
                            // ________________________________________________________________________________________________________
    
    using namespace std;    // weist std als Namensraum aus, d.h. die "Vorsilbe" 'std::' ist nicht nötig
    
    class matrix
      {
        public:    // Die Deklarationen in diesem Abschnitt gelten im gesmaten Programm
        	// Typendeklarationen
             typedef size_t groessenTyp; // groessenTyp wird als neuer Datentyp eingeführt. In diesem Falle als size_t, welches ein vorzeichenloser Ganzzahltyp für size() ist.
             typedef int werteTyp;       // werteTyp wird als neuer Datentyp eingeführt. In diesem Falle als int.
    
            // Konstruktoren
            	// 1. der Standardkonstruktor
               	matrix() : spaltenAnzahl(0), matrixVektor()
            			{}
              // 2. Der Konstruktor der mit den übergebenen Werte die entsprechenden Variablen initialisiert. Hier eine n*m Matrix!
               	matrix(groessenTyp zeilen, groessenTyp spalten, const werteTyp& vorgaengerMatrix = werteTyp()) : spaltenAnzahl(spalten), matrixVektor(zeilen * spalten, vorgaengerMatrix)
              		{}
              // 3. Der Konstruktor der mit den übergebenen Werte die entsprechenden Variablen initialisiert. Hier eine quadratische n*n Matrix!
              	matrix(groessenTyp groesse, const werteTyp& vorgaengerMatrix = werteTyp()) : spaltenAnzahl(groesse), matrixVektor(groesse * groesse, vorgaengerMatrix)
              		{}
    
            // Methoden
               werteTyp* operator[](groessenTyp zeilenNummer)
               	// Diese Funktion erhält eine zeilenNummer und gibt dann die Adresse der Zeile zurück.
                // ________________________________________________________________________________________________________
                  {
                    return &matrixVektor[zeilenNummer * spaltenAnzahl];
                  }
    
                void einfuegen(groessenTyp zeilenNummer, groessenTyp spaltenNummer, const matrix& quellMatrix)
                  // fügt die Matrix quellMatrix ab der Position (zeilenNummer, spaltenNummer) ein
                  {
                    assert(zeilenNummer + quellMatrix.Zeilen() <= Zeilen());      // prüft ob die Zeile  noch hinzugefügt werden darf, wenn nicht, bricht das Proggy mit Fehlermelduung ab
                    assert(spaltenNummer + quellMatrix.Spalten() <= Spalten());   // prüft ob die Spalte noch hinzugefügt werden darf, wenn nicht, bricht das Proggy mit Fehlermelduung ab
    
                    for (vector<werteTyp>::const_iterator quelle = quellMatrix.matrixVektor.begin(); quelle != quellMatrix.matrixVektor.end(); quelle += quellMatrix.Spalten(), ++zeilenNummer)
                      { // eine Zeile kopieren
                        copy(quelle, quelle + quellMatrix.Spalten(), matrixVektor.begin() + zeilenNummer * spaltenAnzahl + spaltenNummer);
                      }
                  }
    
                groessenTyp Zeilen() const
                    // ________________________________________________________________________________________________________
                    {
                      groessenTyp rueckgabeWert;
                      if (matrixVektor.empty())
                        {
                          rueckgabeWert = 0;
                        }
                      else
                        {
                          rueckgabeWert = matrixVektor.size();
                          rueckgabeWert = rueckgabeWert / spaltenAnzahl;
                        }
                    }
                groessenTyp Spalten() const
                  // ________________________________________________________________________________________________________
                  {
                    return spaltenAnzahl;
                  }
    
          friend ostream& operator<<(ostream& ausgabe, const matrix& ausgabeMatrix)
            // --   Ausgabe
            {
              const streamsize breiteDesAusgabeZeichens = ausgabe.width();
              groessenTyp spalte = 0;
              for (vector<werteTyp>::const_iterator matrixVektorZaehler = ausgabeMatrix.matrixVektor.begin(); matrixVektorZaehler != ausgabeMatrix.matrixVektor.end(); ++matrixVektorZaehler, ++spalte)
                {
                  if (spalte == ausgabeMatrix.spaltenAnzahl)
                    {
                      ausgabe << "\n";
                      spalte = 0;
                    }
                  ausgabe << setw(breiteDesAusgabeZeichens) << *matrixVektorZaehler;
                }
              ausgabe << "\n";
              return ausgabe;
            }
    
        private: // Die Deklarationen in diesem Abschnitt gelten nur innerhalb dieser Klasse, bzw. Datei
          groessenTyp spaltenAnzahl;            // Deklaration von spaltenAnzahl als Variable vom Typ groessenTyp für die Anzahl der Spalten bzw. Zeilen (quadratische Matrix)
                                                                                // ________________________________________________________________________________________________________
          vector<werteTyp> matrixVektor;    // Deklaration von matrixVektor als Vektor vom Typ werteTyp
                                                                                // ________________________________________________________________________________________________________
        };
    

    Desweiteren habe ich nun noch versucht eine Unterklasse Stanzmatrix zu erzeugen, leider mit mangelndem Erfolg.

    // -- stanzMatrix.h
    
    #include <vector>
    #include <matrix.h>
    
    using namespace std;
    
    class stanzMatrix : matrix
      {
        public:
            // Konstruktoren
              stanzMatrix()
                {
                  matrix();
                }
              stanzMatrix(groessenTyp groesse, const werteTyp& vorgaengerMatrix = werteTyp())
                {
                  matrix(groesse, vorgaengerMatrix);
                  erzeugeStanzMatrix;
                }
    
            // Methoden
              vector<matrix::werteTyp> stanzAddition(vector& vektor1, vector& vektor2)
                // elementweise zwei Vektoren addieren
                // ________________________________________________________________________________
                {
                  vector<matrix::werteTyp> ausgabeVektor;
                  groessenTyp spalte = 0;
                  for (vector<matrix::werteTyp>::const_iterator vektorZaehler = vektor1.begin(); vektorZaehler != vektor1.end(); ++vektorZaehler, ++spalte)
                    {
                      ausgabeVektor[vektorZaehler] = *vektorZaehler + vektor2[spalte];
                    }
                  return ausgabeVektor;
                }
    
              vector<matrix::werteTyp> stanzMultiplikation(vector& vektor1, matrix& rechenMatrix)
                // elementweise zwei Vektoren addieren
                // ________________________________________________________________________________
                {
                  vector<matrix::werteTyp> ausgabeVektor;
                  groessenTyp spalte = 0;
                  for (vector<werteTyp>::const_iterator matrixVektorZaehler = rechenMatrix.matrixVektor.begin(); matrixVektorZaehler != rechenMatrix.matrixVektor.end(); ++matrixVektorZaehler, ++spalte)
                      {
                        if (spalte == rechenMatrix.spaltenAnzahl)
                          {
                            ausgabeVektor[spalte] = *matrixVektorZaehler * vektor1[spalte];
                            spalte = 0;
                          }
                        }
                  return ausgabeVektor;
                }
    
        private: // Die Deklarationen in diesem Abschnitt gelten nur innerhalb dieser Klasse, bzw. Datei
          matrix::werteTyp erzeugeStanzMatrixElemente(matrix::groessenTyp zeilenPosition, matrix::groessenTyp spaltenPosition)
            {
              return !(spaltenPosition & ~zeilenPosition);
            }
    
          bool erzeugeStanzMatrix()
              {
              groessenTyp spalte = 0;
              groessenTyp zeile = 0;
              for (vector<werteTyp>::iterator matrixVektorZaehler = stanzMatrix.matrixVektor.begin(); matrixVektorZaehler != stanzMatrix.matrixVektor.end(); ++matrixVektorZaehler, ++spalte)
                {
                  *matrixVektorZaehler=erzeugeStanzMatrixElemente(zeile,spalte);
                  if (spalte == stanzMatrix.spaltenAnzahl)
                    {
                      spalte = 0;
                      zeile++;
                    }
                }
              return true;
            }
      };
    

    Der Compiler fängt schon ganz am Anfang an zu meckern 😞

    d:\programme\microsoft visual studio 8\vc\include\matrix.h(30) : error C2011: 'matrix': 'class' Typneudefinition
            d:\programme\microsoft visual studio 8\vc\include\matrix.h(30): Siehe Deklaration von 'matrix'
    d:\programme\microsoft visual studio 8\vc\include\stanzmatrix.h(21) : error C2504: 'matrix': Basisklasse undefiniert
    d:\programme\microsoft visual studio 8\vc\include\stanzmatrix.h(38) : error C2027: Verwendung des undefinierten Typs "matrix"
            d:\programme\microsoft visual studio 8\vc\include\matrix.h(30): Siehe Deklaration von 'matrix'
    

    Dazu einmal die folgenden Zeilen:

    matrix.h:

    29    class matrix 
    30      { 
    31        public:
    

    stanzmatrix.h:

    20    class stanzMatrix : matrix
    21      { 
    22        public: 
    
    ...
    
    38      vector<matrix::werteTyp> stanzAddition(vector& vektor1, vector& vektor2)
    

    Gibt es evtl irgendwo ein kleines Beispielprojekt, das genauso etwas behandelt, also eine Klasse mit einer Unterklasse, wobei man Objekte der Unterklasse erzeugt aber auch Methoden der Oberklasse benutzt?
    Gerade die Konstruktoren sind mir bei der Unterklasse nicht wirklich klar. Und an Beispielen lernt man soetwas nun doch am besten.
    Oder bin ich schon so dicht an der Lösung, daß ihr mir noch ein wenig auf die Sprünge helfen könnt?



  • Hallo bomberking,

    die Kommentare passen so weit. Die typedefs hast Du unbenannt zu

    typedef size_t groessenTyp; // groessenTyp wird als neuer Datentyp eingeführt. In diesem Falle als size_t, welches ein vorzeichenloser Ganzzahltyp für size() ist.
             typedef int werteTyp;       // werteTyp wird als neuer Datentyp eingeführt. In diesem Falle als int.
    

    nun - die Ausdrücke size_type für den Größen-/Index-Typ und value_type für den Element-Typ habe ich mir nicht ausgedacht, sondern es ist in C++ üblich diese beiden Typen so zu nennen. Das verbessert zunächst mal die Lesbarkeit und zum anderen kann es auch notwendig werden, weil andere Konstruktionen der STL sich darauf abstützen. Hier zwar noch nicht, aber bei Erweiterungen Deiner Matrix-Klassen kann das eine Rolle spielen.

    d:\programme\microsoft visual studio 8\vc\include\matrix.h(30) : error C2011: 'matrix': 'class' Typneudefinition
            d:\programme\microsoft visual studio 8\vc\include\matrix.h(30): Siehe Deklaration von 'matrix'
    

    liegt wahrscheinlich daran, dass Deine H-Dateien keinen Re-Include-Schutz besitzen. das geht so

    // -- H-Datei ..
    #ifndef DATEINAME_H   // z.B. #ifndef STANZMATRIX_H - beliebig aber eindeutig
    #define DATEINAME_H
    // .. Inhalt der H-Datei
    #endif
    

    diese Konstruktion verhindert, dass eine H-Datei mehrfach inkludiert wird.

    Daneben hat Dein Code noch einige offensichtliche Fehler

    - In der Klasse matrix musst Du aus dem 'private' vor den Membern ein 'protected' machen, damit Du von der Unterklasse darauf zugreifen kannst.

    - In stanzMatrix sollte die Ableitung public sein, sonst kannst Du von außen nicht auf die Methoden der Oberklasse (matrix) zugreifen. Also

    class stanzMatrix : public matrix
    {
    

    - bei der Methode stanzAddition hast Du die Template-parameter vergessen

    //          vector<matrix::werteTyp> stanzAddition(vector& vektor1, vector& vektor2)
        vector< matrix::werteTyp > stanzAddition( const vector< matrix::werteTyp >& vektor1, const vector< matrix::werteTyp >& vektor2)
    

    außerdem solltest Du Objekte, die Du innerhalb der Methode/Funktion nicht änderst immer als const Reference übergeben.

    - in stanzAddition

    //                  ausgabeVektor[vektorZaehler] = *vektorZaehler + vektor2[spalte];
                ausgabeVektor.push_back( *vektorZaehler + vektor2[spalte] );
    

    wenn ein vector angelegt ist, so ist er leer. Möchtest Du Elemente (hinten) hinzufügen so geht das am einfachsten mit 'push_back'. Der Zugriff über [] führt immer zu einem Fehler, da der vector leer ist.

    - die letzten beiden Punkte gelten genauso für stanzMultiplikation

    - in erzeugeStanzMatrixElemente kannst Du direkt auf die Member der Oberklasse zugreifen

    //        for (vector<werteTyp>::iterator matrixVektorZaehler = stanzMatrix.matrixVektor.begin(); matrixVektorZaehler != stanzMatrix.matrixVektor.end(); ++matrixVektorZaehler, ++spalte)
            for (vector<werteTyp>::iterator matrixVektorZaehler = matrixVektor.begin(); matrixVektorZaehler != matrixVektor.end(); ++matrixVektorZaehler, ++spalte)
    

    Nun zu den Konstruktoren. Korrekt wäre

    // Konstruktoren
        stanzMatrix()
            : matrix()
        {}
        stanzMatrix( groessenTyp groesse, const werteTyp& vorgaengerMatrix = werteTyp() )
            : matrix( groesse, groesse, vorgaengerMatrix )  // immer quadratisch
        {
            erzeugeStanzMatrix();
        }
    

    Informiere Dich mal über das Thema Initialisierungslisten.

    Und zum Schluß noch eine andere Bemerkung. Aus Deinen vorhergehenden Postings weiß ich, dass Du zu einer Zeit immer nur eine Zeile dieser 'StanzMatrix' benötigst. Wenn Du uns zeigst, was Du damit tust, kann ich Dir eine Lösung zeigen, bei der Du beide Matrizen-Klassen gar nicht mehr brauchst.
    Aber 'ne gute Übung ist das trotzdem.

    Gruß
    Werner



  • Hallo Werner,

    Werner Salomon schrieb:

    die Kommentare passen so weit. Die typedefs hast Du unbenannt
    ...
    nun - die Ausdrücke size_type für den Größen-/Index-Typ und value_type für den Element-Typ habe ich mir nicht ausgedacht, sondern es ist in C++ üblich diese beiden Typen so zu nennen.

    ah, gut!.
    Ich dachte, das wären von dir willkürlich gewählte Namen.
    Prinzipiell habe ich mir angewöhnt, selbstvergebene Namen in Deutsch zu wählen, damit ich leichter meinen eigenen "Mist" von den Standard unterscheiden kann 😉

    Werner Salomon schrieb:

    ... Re-Include-Schutz besitzen. das geht so
    ...
    diese Konstruktion verhindert, dass eine H-Datei mehrfach inkludiert wird.

    ah, gut. Das schau ich mir nochmal an. Da hatte sich mir zuerst der Sinn noch nicht erschlossen.

    Werner Salomon schrieb:

    - In der Klasse matrix musst Du aus dem 'private' vor den Membern ein 'protected' machen, damit Du von der Unterklasse darauf zugreifen kannst.

    also ist 'protected' ein "private" für Unterklassen?

    Werner Salomon schrieb:

    - In stanzMatrix sollte die Ableitung public sein, sonst kannst Du von außen nicht auf die Methoden der Oberklasse (matrix) zugreifen. Also
    ...
    - bei der Methode stanzAddition hast Du die Template-parameter vergessen

    uups, naja, solche Flüchtigkeitsfehler sind nicht untypisch für mich 😉
    ABer die hätte ich vermutlich noch mithilfe des Compilers gefunden

    Werner Salomon schrieb:

    außerdem solltest Du Objekte, die Du innerhalb der Methode/Funktion nicht änderst immer als const Reference übergeben.

    OK, das werde ich auch übernehmen, klingt besser. Allerdings kannte ich diese Option vorher noch nicht.

    Werner Salomon schrieb:

    wenn ein vector angelegt ist, so ist er leer. Möchtest Du Elemente (hinten) hinzufügen so geht das am einfachsten mit 'push_back'. Der Zugriff über [] führt immer zu einem Fehler, da der vector leer ist.

    hmm, ebenso könnte ich aber doch auch zurst den vektor1 in den ausgabevektor kopieren und dann per [] manipulieren, oder?

    Werner Salomon schrieb:

    Informiere Dich mal über das Thema Initialisierungslisten.

    hast du da ein paar gute Quellen oder Links?

    Werner Salomon schrieb:

    Und zum Schluß noch eine andere Bemerkung. Aus Deinen vorhergehenden Postings weiß ich, dass Du zu einer Zeit immer nur eine Zeile dieser 'StanzMatrix' benötigst. Wenn Du uns zeigst, was Du damit tust, kann ich Dir eine Lösung zeigen, bei der Du beide Matrizen-Klassen gar nicht mehr brauchst.

    naja, im Prinzip muss ich diese stanzaddition und stanzmulitplikation für alle n*n-Matrizen durchführen (bis n=?).

    Werner Salomon schrieb:

    Aber 'ne gute Übung ist das trotzdem.

    DAS ist auch der Hauptgrund dieser Aufgabe.
    Ich bereit mich gerade auf eine größere Aufgabe vor, und brauche dafür jede Menge Übung.

    Auch wenn das jetzt mit Kanonen auf Spatzen schießen ist, es hilft mir ungemein beim Verständnis, da ein praktisches Beispiel immer das Beste ist.



  • Hallo Werner,

    bomberking schrieb:

    Werner Salomon schrieb:

    ... Re-Include-Schutz besitzen. das geht so
    ...
    diese Konstruktion verhindert, dass eine H-Datei mehrfach inkludiert wird.

    ah, gut. Das schau ich mir nochmal an. Da hatte sich mir zuerst der Sinn noch nicht erschlossen.

    so, is nun erledigt.
    Habe nochmal ein wenig in einem Buch geschmöckert.
    Wenn man weiß was man suchen muss, ist es nur halbso wild 🙂

    bomberking schrieb:

    Werner Salomon schrieb:

    - In der Klasse matrix musst Du aus dem 'private' vor den Membern ein 'protected' machen, damit Du von der Unterklasse darauf zugreifen kannst.

    also ist 'protected' ein "private" für Unterklassen?

    Auch erledigt.

    Erstmal vielen Dank 👍

    Ein Problem gibtes aber wohl noch.

    1>h:\c++_console\stanzmatrix\stanzmatrix\stanzmatrix.cpp(64) : error C2352: 'matrix::zeile': Unzulässiger Aufruf einer nicht statischen Memberfunktion
    1>        e:\programme\microsoft visual studio 8\vc\include\matrix.h(70): Siehe Deklaration von 'matrix::zeile'
    1>h:\c++_console\stanzmatrix\stanzmatrix\stanzmatrix.cpp(65) : error C2352: 'stanzMatrix::stanzMultiplikation': Unzulässiger Aufruf einer nicht statischen Memberfunktion
    1>        e:\programme\microsoft visual studio 8\vc\include\stanzmatrix.h(51): Siehe Deklaration von 'stanzMatrix::stanzMultiplikation'
    1>h:\c++_console\stanzmatrix\stanzmatrix\stanzmatrix.cpp(66) : error C2352: 'stanzMatrix::stanzAddition': Unzulässiger Aufruf einer nicht statischen Memberfunktion
    1>        e:\programme\microsoft visual studio 8\vc\include\stanzmatrix.h(38): Siehe Deklaration von 'stanzMatrix::stanzAddition'
    

    und noch die dazugehörigen Stellen.
    Irgendwie klappen wohl die Funktionsaufrufe nicht.
    Ich vermute mal für ein C++-Crack eine Trivialität, aber für mich noch nicht verständlich 😞
    matrix.h

    class matrix 
      { 
        public:
    ...
    
          vector<werteTyp> zeile(const groessenTyp& zeilenNummer, const matrix& ausgabeMatrix)
            {
              ...
            }
    
    ...
    

    berechnung.cpp

    ...
        for (matrix::groessenTyp h=0; h < anzahlErzeugendeElemente; h++)
          {
    	zwischenVektor02.clear();
    	zwischenVektor03.clear();
    	zwischenVektor04.clear();
    	zwischenVektor04 = stanzMatrix::zeile((matrix::groessenTyp) h + 1, aktuelleStanzMatrix);
    	zwischenVektor03 = stanzMatrix::stanzMultiplikation(zwischenVektor04, rechenVektor01);
    	zwischenVektor02 = stanzMatrix::stanzAddition(zwischenVektor01, zwischenVektor03);
    	zwischenVektor01 = zwischenVektor02;
    	zwischenVektor02.clear();
    	zwischenVektor03.clear();
    	zwischenVektor04.clear();
          }
    
    ...
    


  • bomberking schrieb:

    Werner Salomon schrieb:

    Informiere Dich mal über das Thema Initialisierungslisten.

    hast du da ein paar gute Quellen oder Links?

    siehe http://de.wikipedia.org/wiki/Initialisierungsliste



  • Moin Werner,

    Werner Salomon schrieb:

    bomberking schrieb:

    Werner Salomon schrieb:

    Informiere Dich mal über das Thema Initialisierungslisten.

    hast du da ein paar gute Quellen oder Links?

    siehe http://de.wikipedia.org/wiki/Initialisierungsliste

    *uups*
    solangsam muss ich vor Wikipedia echt den Hut ziehen.
    Bei einer Programmiersprache wäre ich nun nie auf die Idee gekommen, daß ich da Hilfe finden kann.
    Das andere Problem ist nun auch schon gelöst.
    Das war mal wieder der berühmte Wald den man vor lauter Bäumen nicht sieht 😉



  • bomberking schrieb:

    Ein Problem gibtes aber wohl noch.

    1>h:\c++_console\stanzmatrix\stanzmatrix\stanzmatrix.cpp(64) : error C2352: 'matrix::zeile': Unzulässiger Aufruf einer nicht statischen Memberfunktion
    1>        e:\programme\microsoft visual studio 8\vc\include\matrix.h(70): Siehe Deklaration von 'matrix::zeile'
    1>h:\c++_console\stanzmatrix\stanzmatrix\stanzmatrix.cpp(65) : error C2352: 'stanzMatrix::stanzMultiplikation': Unzulässiger Aufruf einer nicht statischen Memberfunktion
    1>        e:\programme\microsoft visual studio 8\vc\include\stanzmatrix.h(51): Siehe Deklaration von 'stanzMatrix::stanzMultiplikation'
    1>h:\c++_console\stanzmatrix\stanzmatrix\stanzmatrix.cpp(66) : error C2352: 'stanzMatrix::stanzAddition': Unzulässiger Aufruf einer nicht statischen Memberfunktion
    1>        e:\programme\microsoft visual studio 8\vc\include\stanzmatrix.h(38): Siehe Deklaration von 'stanzMatrix::stanzAddition'
    

    Hallo bomberking,

    matrix::zeile ist eine Methode der Klasse matrix. Dann kannst Du diese nur von einem Objekt der Klasse matrix aufrufen. Zum Beispiel so

    stanzmatrix m(...);
        // ..
        zwischenVektor04 = m.zeile((matrix::groessenTyp) h + 1, aktuelleStanzMatrix);
    

    Ist der Code inerhalb einer Methode von stanzmatrix, so kannst Du eine Methode von matrix so aufrufen, als ob es eine Methode von stanzmatrix wäre - wegen der Vererbung (es sei denn sie ist private).

    // Methode von stanzmatrix; rufe zeile von matrix wie eigene Methode
        zwischenVektor04 = zeile((matrix::groessenTyp) h + 1, aktuelleStanzMatrix);
    

    Für die anderen Fehlermeldungen gilt das gleiche

    Gruß
    Werner



  • Hallo @all,
    nach längerer Zeit arbeite ich mal wieder an diesem Programm weiter.
    Und habe auch prompt wieder ein Problem.
    und zwar möchte ich zwei Vektoren bzgl ihrer Länge vergleichen.
    Mich interessieren dabei nur drei Fälle: a>b, a=b, a<b.
    Anbei ein paar Codeschnipsel:

    using namespace std;
    
    bool berechne(const bool graphen, const vector<matrix::werteTyp> rechenVektor, const vector<matrix::werteTyp> rechenVektorALT)
    	{ 
        vector<matrix::werteTyp> rechenVektor01;
        vector<matrix::werteTyp> rechenVektor02;
        vector<matrix::werteTyp> zwischenErgebnisVektor;
        stanzMatrix aktuelleStanzMatrix;
        int rechenVektorHalbeLaenge;
        matrix::groessenTyp laenge;
        laenge = rechenVektor.size();
    
        printf("P(%2d, %2d) = <", ausgabeN, ausgabeK);
    					}
        if (ausgabeK == (anzahlErzeugendeElemente+1))
          {
    	ausgabeN++;
    	ausgabeK--;
          }
        else 
          {
    	if (rechenVektorALT.size() == rechenVektor.size())
    	  {
    	    ausgabeN--;
    	    ausgabeK++;
    	  }
    	else if (rechenVektorALT.size() < rechenVektor.size())
    	  {
    	    ausgabeN--;
    	    ausgabeK++;
    	  }
    	else if (rechenVektorALT.size() > rechenVektor.size())
    	  {
      	    ausgabeN++;
    	    ausgabeK--;
    	  }
            for (vector<matrix::werteTyp>::const_iterator vektorZaehler = rechenVektor.begin(); vektorZaehler != rechenVektor.end(); ++vektorZaehler) 
                { 
                  cout << " " << *vektorZaehler; 
                } 
            cout << " >\n";
          }
        rechenVektorHalbeLaenge = (int) laenge;
        rechenVektorHalbeLaenge /= 2;
        if (rechenVektorHalbeLaenge>0)
          {
            for (matrix::groessenTyp h=0; h < rechenVektorHalbeLaenge; h++)
              {
                rechenVektor01.push_back(rechenVektor[h]);
                rechenVektor02.push_back(rechenVektor[rechenVektorHalbeLaenge+h]);
              }
          }
        else
          {
            rechenVektor01.push_back(0);
            rechenVektor02.push_back(1);
          }
        aktuelleStanzMatrix = stanzMatrix::stanzMatrix((matrix::groessenTyp) rechenVektorHalbeLaenge, 1);
        if (debug_Ausgabe) 
          cout << aktuelleStanzMatrix << endl;
        for (matrix::groessenTyp h=1; h <= rechenVektorHalbeLaenge; h++)
         {
           zwischenErgebnisVektor = aktuelleStanzMatrix.stanzAddition(aktuelleStanzMatrix.stanzMultiplikation(aktuelleStanzMatrix.zeile((matrix::groessenTyp) h), rechenVektor02), rechenVektor01);
         }
        if (zwischenErgebnisVektor.size()>1) 
          {
            alteLaenge = laenge;
            berechne(graphen, zwischenErgebnisVektor, rechenVektor);
          }
        else if (zwischenErgebnisVektor.size()==1)
          {
            ergebnisVektor.push_back(zwischenErgebnisVektor[0]); 
          }
        else
          {
            cout << "ENDE\n";
          }
        return true;
      }
    

    Das Problem ist, selbst wenn in der Zeile

    if (rechenVektorALT.size() == rechenVektor.size())
    

    die beiden Vektoren identisch sind, erkennt VC das nicht und geht in einen der beiden else-Fälle.
    Gibt es evtl bekannte Probleme mit size?
    Oder bin ich zu doof?
    Oder wende ich size einfach nur falsch an?


Anmelden zum Antworten