verbesserungsvorschläge für endlich fertig gestellte klasse
-
#ifndef matrix_klasse #define matrix_klasse #include <iostream> #include <cstdlib> using namespace std; template <class T> class matrix { public: matrix(unsigned int z); //eine dimension matrix(unsigned int z, unsigned int s); //zwei dimemsionen //matrix(int, int, int); //noch nicht ~matrix(); void ausgabe_matrix(); void setze_in_matrix(T *feld, unsigned int zeilen_matrix); //schiebt hinten rein(matrix) void setze_in_matrix(T *feld, unsigned int zeilen_matrix, int pos_z); //für eindim array void setze_in_matrix(T *feld, unsigned int zeilen_matrix, unsigned int spalten_matrix, int pos_z, int pos_s); //für zweidim matrix void fuege_array_ein(T *array); private: T *matrix_eindim; T **matrix_zweidim; //T ***matrix_dreidim; unsigned int zeilen_matr; unsigned int spalten_matr; unsigned int index_z_eindim; //damit verwechlungen ausgeschlossen sind unsigned int index_z_zweidim; unsigned int index_s_zweidim; }; //############################################################################## template <class T> matrix<T>::matrix(unsigned int zeilen) { index_z_eindim = 0; matrix_eindim = new T[zeilen]; zeilen_matr = zeilen; } template <class T> matrix<T>::matrix(unsigned int zeilen, unsigned int spalten) { index_z_zweidim = 0; index_s_zweidim = 0; matrix_zweidim = new T*[zeilen]; for(int i=0; i < zeilen; i++) matrix_zweidim[i] = new T[spalten]; zeilen_matr = zeilen; spalten_matr = spalten; } template <class T> matrix<T>::~matrix() { delete [] matrix_eindim; delete [] matrix_zweidim; //delete matrix_dreidim; } template <class T> void matrix<T>::ausgabe_matrix() { for(unsigned int i = 0; i < zeilen_matr; i++) cout<< "Position " << i << ": " << matrix_eindim[i] << endl; } template <class T> void matrix<T>::setze_in_matrix(T *feld, unsigned int feld_zeilen) { for(unsigned int i = 0; i < feld_zeilen; ++i && ++index_z_eindim) matrix_eindim[index_z_eindim] = feld[i]; } template <class T> void matrix<T>::setze_in_matrix(T *feld, unsigned int feld_zeilen, int position_zeile) { int j = 0; for(unsigned int i = position_zeile; i < (feld_zeilen + position_zeile); i++) { matrix_eindim[i] = feld[j]; ++j; } if( (feld_zeilen + position_zeile) > index_z_eindim) index_z_eindim = (feld_zeilen + position_zeile); } template <class T> void matrix<T>::setze_in_matrix(T *feld, unsigned int feld_zeilen, unsigned int feld_spalten, int position_zeile, int position_spalte) { index_z_zweidim += position_zeile; index_s_zweidim += position_spalte; for(; index_z_zweidim < feld_zeilen; index_z_zweidim++) for(; index_s_zweidim < feld_spalten; index_s_zweidim++) matrix_zweidim[index_z_zweidim][index_s_zweidim] = feld[index_z_zweidim][index_s_zweidim]; } #endif
-
letzte funktion nicht beachten, die ist anders geplant
-
Dein Destruktor ist schon wieder falsch!
Mit delete [] matrix_zweidim schickst Du nur die Zeiger ins Nirvana aber nicht das worauf sie zeigen.
Gruss
turing
-
schonwieder, mmh in meinem buch hat der autor das auch so gemacht.
müsste das dann "[][]" heißen oder muss ich das mit ner schleife deleten?
-
#ifndef matrix_klasse #define matrix_klassediese bezeichner sollen was sein, wo du sicher bist, daß du sie nicht woanders aus versehen verwendest. deswegen nehme ich MATRIX_H. und ich nehme bezeichner mit _H am ende nur für include-guards. soll nicht heßen, daß du auch _H nehmen sollst. sollst nur schauen, ob mit deinem restlichen stil sicher ist, daß du matrix_klasse nicht woanders verwendest.
#include <iostream> #include <cstdlib>fein.
using namespace std;nicht fein. mach nie im haeder using namespace. was ist, wenn du mal ne andere lib mit nem anderen cout verwenden möchtest? oder nur ein anderes swap? durch dein using namespace erzwingst du, daß jeder benutzer deiner matrix-klasse auch using namespace std; gemacht hat, auch wenn er eientlich lieber using namespace vhlib; machen würde und beide nicht nebeneinander gehen.
template <class T> class matrix {naja, ich mag grossbuchstaben.
public:bitte zeig zuerst den private-teil mit den attributen. so kann ein fremder leser viel schneller raffen, was die klasse ist und was sie macht.
matrix(unsigned int z); //eine dimension matrix(unsigned int z, unsigned int s); //zwei dimemsionendas ist schlimm. mach matrix und matrix2d und matrix3d als getrennte klassen. damit kriegste mehr performance und mehr zurgiffssicherheit.
//matrix(int, int, int); //noch nicht ~matrix();fein
void ausgabe_matrix();lieber void print_at(ostream& out);, damit man auch mal in ne datei schreiben kann, wenn einem lustig danach ist.
void setze_in_matrix(T *feld, unsigned int zeilen_matrix); //schiebt hinten rein(matrix) void setze_in_matrix(T *feld, unsigned int zeilen_matrix, int pos_z); //für eindim array void setze_in_matrix(T *feld, unsigned int zeilen_matrix, unsigned int spalten_matrix, int pos_z, int pos_s); //für zweidim matrix void fuege_array_ein(T *array);vielleicht isses netter (nee, sicher, nicht nur vielleicht), wenn du den op[] bzw op[][] bzw op[][][] überlädst?
private: T *matrix_eindim; T **matrix_zweidim; //T ***matrix_dreidim;gleichzeitig???
unsigned int zeilen_matr; unsigned int spalten_matr; unsigned int index_z_eindim; //damit verwechlungen ausgeschlossen sind unsigned int index_z_zweidim; unsigned int index_s_zweidim;ich sag's doch. mehrere klassen, dann verwechslt sich auch nix.
}; //##############################################################################fein.
template <class T> matrix<T>::matrix(unsigned int zeilen) { index_z_eindim = 0; matrix_eindim = new T[zeilen]; zeilen_matr = zeilen; }och, was triviales kannste doch auch inline in der klasse anbieten.
template <class T> matrix<T>::matrix(unsigned int zeilen, unsigned int spalten) { index_z_zweidim = 0; index_s_zweidim = 0; matrix_zweidim = new T*[zeilen]; for(int i=0; i < zeilen; i++) matrix_zweidim[i] = new T[spalten]; zeilen_matr = zeilen; spalten_matr = spalten; }wieder verwirrend, weil die klasse irgendwie zwei aufgaben hat.
ach, was sage ich, die hat 6 aufgaben.also mach erstmal aus den drei matrix-aufgaben auch drei klassen. dann trenne die speicher-haltungs-klasse von der matrix-zugriffs-klasse.
rest brauche ich nicht mehr zu lesen, hast erstmal ein paar vorschläge.
-
delete mit einer Schleife
Und noch ein paar Designaspekte: Deine Ewig_Lange_Elementfunktionnamen_die_ueberhaupt_nichts_aussagen_sind_auch_nicht_gut
Überlege Dir kurze und prägnante Namen:
Beispiel:
Matrix<int> my_matrix(...) ... my_matrix.setze_in_zeile(...) my_matrix.ausgabe_matrix()hört sich nicht so toll an
wie wäre es mit
Matrix<int> my_matrix(...) ... my_matrix.redefineRow(...) my_matrix.print()Ausserdem ist es aus Performancegründen sicher sinnvoll gleich ganze Blöcke zu kopieren statt alles elementweise.
Mir fällt noch eine ganze Menge mehr ein, was ich verbessern würde. Aber darüber können wir gerne morgen diskutieren, bin jetzt platt.
PS: Was ist das für ein Buch?
Gruß
turing
-
print_at(ostream& out);
warum kein operator<<?
-
danke ich werde deine ratschläge bis morgen umsetzen und dann die klasse/n posten.
nur eins noch, ich weiß mit der ausgabefunktion nicht so recht viel anzufangen
wie müsste das hier richtig aussehen
:void matrix<T>::print_at(std::ostream& ausgabe); { //if(spalten_matr < 1) for(unsigned int i = 0; i < zeilen_matr; i++) (std::cout.ausgabe<<("Position ")).ausgabe<<(i); (std::cout.ausgabe<<(": ").ausgabe<<(matrix_eindim[i]); (std::cout.ausgabe<<(std::endl) ); /* else { for(unsigned int i = 0; i < zeilen_matr; i++) { cout<<endl; for(unsigned int j = 0; j < spalten_matr; j++) cout<< "Position " << i << ": " << matrix_zweidim[i][j]; } } */ return ausgabe; }
-
strings schrieb:
print_at(ostream& out);
warum kein operator<<?
ach, den hab ich doch glatt vergessen.
ostream& operator<<(ostream& out,Matrix const& m){ return m.printAt(out); }und weil ich irgendwo sowas wie
template<typename T> ostream& operator<<(ostream& out,T const& t){ return t.printAt(out); }stehen habe, reicht's bei mir immer, nur eine printAt anzubieten, wenn ich eine klasse ausgebbar machen mag.
-
warum denn dann 2 methoden für die ausgabe??
-
strings schrieb:
warum denn dann 2 methoden für die ausgabe??
die printAt()-Methode brauchst du wenn du ein objekt polymorph ausgeben willst, virtual funktioniert leider bei normalen Funktionsaufrufen nicht.
der template-wrapper ist ne gute idee

-
Volkard du hast ja echt VIEL Zeit
Und bitte_bitte_bitte verwende doch Englisch im Code wirkt viel professioneller und ist mit der Zeit besser und auch von allen in der gesamten Welt besser zu lesen.
-
T *matrix_eindim; T **matrix_zweidim;Und warum machst du in einer Matrixklasse ein und zweidimensionale Matrizen. Normalerweise hast du eine Klasse Matrix2d Matrix3d Matrix4d... Was ist auch bitte eine 1dimensionale Matrix? kannst ja gleich nen float nehmen?
-
dali schrieb:
Was ist auch bitte eine 1dimensionale Matrix? kannst ja gleich nen float nehmen?
nee. ein float ist 0d.
-
[quote="dali"]Volkard du hast ja echt VIEL Zeit ;)[quote]
ich habe VIEL zu wenig zeit.Und bitte_bitte_bitte verwende doch Englisch im Code
das mache ich manchmal. mit welchem code haste im moment ein problem?
wirkt viel professioneller
ich lege nicht extrem viel wert darauf, durch irgendwas professioneller zu wirken, als ich bin. besonders im code nicht. den mache ich so gut und so lesbar unter nichtvernachlässigung von ein wenig erweiterbarkeit und performance, wie ich kann. im allgemeinen mache ich projektübergreifend wiederverwendbares auf englisch und domain-spezifisches auf deutsch. das ergibt auch eine schöne und augenfällige schichtentrenung. einfach köstlich.
und ist mit der Zeit besser und auch von allen in der gesamten Welt besser zu lesen.
da ich eh keine kommentare mache, ist das problem schon fast aus der welt. *g*
-
Das mit dem Englisch war eigentlich auf exigoner bezogen. Ist sicher Geschmackssache was man verwendet aber Englisch und Deutsch mixen find ich nicht gut... Und Code ohne Kommentare naja... Mir hat man immer Punkte bei den Übungen abgezogen

-
So noch ein bisschen (?) Matrixdesign.
Was willst Du eigentlich mit der Matrix machen? Ich kenne Matrizen in erster Linie aus der diskreten Mathematik oder Numerik.
Für einen Datentyp Matrix (der in dem o.g. Kontext eingesetzt werden soll) bietet sich an:
1.) Betreibe zuerst Matrixdesign
Das Wichtigste. Überlege Dir zuerst ganz genau, was die Matrix können soll und "make the common case fast".
2.) Implementiere nur den Datentyp Matrix.
Es gibt keine "eindimensionale" oder "zweidimensionale" Matrix, in dem Sinne wie es hier verwendet wird. Eine Matrix besteht immer (!) aus Zeilen und Spalten.
Und deswegen gibt es nur "zweidimensionale" Matrizen.
Bsp:
[1 0] ist eine (1x2)-Matrix
[1 0; ist eine (2x2)-Matrix
[0 1]
[1] ist eine (1x1)-MatrixDie Dimension einer Matrix ist übrigens die Anzahl der linear unabhängigen Zeilen bzw. Spalten.
3.) Repräsentiere den Inhalt der Matrix als doppelt verkettete Liste.
Das mag vielleicht auf den ersten Blick wie Speicherverschwendung aussehen, ist aber tatsächlich, was übliche Matrixoperationen angeht, wesentlich effizienter. Du kannst Dir ja als Übung überlegen, warum.
Hier nur ein paar Hinweise:
- Hinzufügen von Zeilen/Spalten wird einfacher
- Löschen von Zeilen/Spalten wird einfacher
- Tauschen von Zeilen/Spalten wird einfacher
- Transponieren wird einfacher
- Matrix-Matrix Multiplikation wird einfacher
- Gaussalgorithmus wird einfacher
- Konsistenes Prüfen auf NULL-Zeiger4.) Wähle eine einfach Schnittstelle
Neben Kontruktor/Destruktor muss die Matrix eigentlich nur +, -, * (und /) sowie Zeilen/Spalten Manipulationen beherrschen. Weitere Elementfunktionen würde ich nur aufnehmen wenn Du sie wirklich häufig brauchst, ansonsten auslagern.
5.) Programmiere einfach und effizient
Auch sehr wichtig. Ständiges Hin- und Herkopieren von irgendwelchen Werten ist ziemlich laaaaaaaangsam (stattdessen ein paar Zeiger verbiegen). Ebenso ständiges new und delete (lieber Puffer und Speicherpools verwenden). Überprüfe immer wieder, ob es nicht auch einfacher geht.
So genug Lehrmeisterei. Das hat vielleicht sogar ein bisschen zu weit geführt, sollte Dir aber auch zeigen, dass selbst so etwas einfach Erscheinendes wie eine Matrix verdammt schwer zu implementieren ist. Aber es reicht ja schon, wenn Du einfach ein paar Ideen bekommen hast, wie Du Deine Matrixklasse verbessern
kannst.Wenn jemand Spass daran hat und ein wenig Langeweile, kann sie/er ja mal versuchen eine effiziente Matrixklasse zu implementieren, die die üblichen Operationen darauf unterstützt und dann zum Beispiel an Bitmaps austesten.
Schonmal versucht, alle Eigenvektoren einer Bitmap zu bestimmen? Oder gar zu invertieren?Gruss
turing
-
die ganzen ratschläge lassen sich ja gut umsetzen, aber ich verstehe die ausgabefunktion einfach nicht.
packe ich das in meine klassestd::ostream& operator<<(std::ostream& out, matrix const& m) return m.printAt(out);beomme ich fehler
-
Turing schrieb:
3.) Repräsentiere den Inhalt der Matrix als doppelt verkettete Liste.
Das mag vielleicht auf den ersten Blick wie Speicherverschwendung aussehen, ist aber tatsächlich, was übliche Matrixoperationen angeht, wesentlich effizienter. Du kannst Dir ja als Übung überlegen, warum.
Hier nur ein paar Hinweise:
[...]
- Matrix-Matrix Multiplikation wird einfacher
- Gaussalgorithmus wird einfacherBegründung?
Was dagegen spricht:
- Speicherverbrauch wird bei dichtbesetzten Matrizen viel höher
- Index-Zugriffe werden langsamerNene, verkettet bitte nur bei großen dünnbesetzten Matrizen.
Im Idealfall hat man mehrere Matrixklassen in der Schublade aus denen man je nach Anwendungsfall wählen kann:
- Eine dynamische wenn die Dimensionen erst zur Laufzeit bekannt sind.
- Eine generische, wenn die Dimensionen zur Compilezeit feststehen.
- Mehrere für dünnbesetzte Matrizen die verkettet, mit einer Hashtable oder ganz anders implementiert sind, je nach Aufbau der Matrix.
- ...
-
ich werd erstmal keine verketteten listen benutzen um ne basisklasse zu schreiben, vielleicht später zum ausprobieren, aber niccht jetzt.