El siguiente es el primer ejercicio que hice con matrices. Quizás alguno de estos ejercicios te puedan servir como una base. Puedes leer el post anterior sobre vectores, matrices y punteros si aún no haz trabajo con ellos.
Recomiendo que intentes y practiques mucho antes de copiar y pegar. Si te sientes estancado en algún problema recién trata de buscar una guía para llegar a la solución.
Esta clase matriz tendrá 3 atributos: Matriz,número de filas y número de columnas. Tiene un constructor por defecto,constructor copiador y un constructor por parámetro que recibe el número de filas y columnas.
Las siguientes funciones fueron implementadas:
- Generar una matriz dinámicamente
- LLenar la matriz desde teclado:
- Llenar la matriz aleatoriamente:
- Imprimir la matriz
- Hallar el mayor elemento.
- Hallar el menor elemento.
- Hallar la moda.
- Intercambiar filas.
- Intercambiar columnas.
- Sumar otra matriz: Sumar 2 objetos de tipo matriz retornar otra matriz. Ejem: c = a + b.
- Restar otra matriz: Igual que la suma. Ejem: c= a – b
- Multiplicar por otra matriz: Ejem: c = a * b. El nro de filas de a debe ser igual al nro de columnas de b
- Multiplicar por un escalar: Ingreso un número y todos los elementos de la matriz se multiplican por ese número.
- Hallar matriz transpuesta: matr[m][n] su transpuesta es matr[n][m]. Se obtiene cambiando filas por columnas. Donde los elementos de la fila m ahora pertenecen a la columna m de la transpuesta.
- Verificar si es simétrica: Una matriz es simétrica si es cuadrada(filas=columnas) y cuando su transpuesta es igual a su matriz original.
- Verificar si es identidad: Es identidad si tiene todos sus elementos nulos excepto los de la diagonal principal que son iguales a 1.
NOTA: He aplicado un poco de templates para manejar la matriz con varios tipos de datos (int, float, char,double) y sobrecarga de operadores para la suma, resta y multiplicación de matrices.
Recien estoy aprendiendo a usar estas 2 características importantes del lenguaje (templates y sobrecarga de operadores) por lo tanto, estos temas serán tratados a profundidad el proximo año.
En breve:
Un template es una manera de que funciones, clases métodos puedan ser usados con varios tipos de datos. Imagínense crear una lista de datos y tener que crear funciones insertar, eliminar, buscar, concatenar, etc para cada tipo de dato. Si los métodos y la clase tienen la misma lógica para que reescribir código si podemos reutilizar.
La sobrecarga de operadores es una manera de realizar las mismas operaciones que solemos hacer con tipos de datos comunes con tipos abstractos de datos. Por ejemplo, la sobrecarga me permitió sumar 2 objetos de tipo Matriz y almacenar el resultado en otro objeto Matriz, del modo c = a + b
Al grano:
Definición de la clase Matriz (La cabecera o header):
matriz.h
#ifndef MATRIZ_H
#define MATRIZ_H
#include <iostream>
#include <time.h>
using namespace std;
template <class T>
class Matriz
{
private:
T mayor_,menor_,moda_,ele,**matr1;
int dim_matriz;
public:
int fils,cols;
T escalar;
Matriz();
Matriz(int,int);
Matriz(const Matriz &m);//constructor copia
void llenar_teclado();
void llenar_aleatorio();
void imprimir();
T mayor();
T menor();
T moda();
void inter_filas(int,int);
void inter_cols(int,int);
bool esSimetrica();
bool esIdentidad();
void multi_escalar(T);
void transpuesta();
Matriz<T> operator+ (const Matriz &matr2);
Matriz<T> operator- (const Matriz &matr2);
Matriz<T> operator* (const Matriz &matr2);
void eliminar();
~Matriz();
protected:
};
#endif // MATRIZ_H
Implemetanción de la clase:
matriz.cpp
#include "Matriz.h"
//Constructor por defecto
template<typename T>
Matriz<T>::Matriz()
{
fils=4;
cols=4;
}
//Constructor copia
template<typename T>
Matriz<T>::Matriz(const Matriz &m)
{
*this = m;
}
//Constructor por parametro
template<typename T>
Matriz<T>::Matriz(int fils_ , int cols_)
{
fils = fils_;
cols = cols_;
matr1 = new T*[fils];
for(int i=0;i<fils;i++){
matr1[i] = new T[cols];
}
}
//Llenar aleatoriamente una matriz
template<typename T>
void Matriz<T>::llenar_aleatorio()
{
//srand(time(NULL));
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
matr1[i][j] = rand() % 30;
}
}
mayor_= matr1[0][0];
menor_= matr1[0][0];
srand(time(NULL));
}
//Llenar una matriz desde teclado
template<typename T>
void Matriz<T>::llenar_teclado()
{
for(int i=0;i<fils;i++){
cout << "Fila " << i+1 << endl;
for(int j=0;j<cols;j++){
cout << "Ingresa el elemento " << j+1 << endl;
cin >>ele;
matr1[i][j] = ele;
}
cout << endl;
}
mayor_= matr1[0][0];
menor_= matr1[0][0];
}
//Imprimir matriz
template<typename T>
void Matriz<T>::imprimir()
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
cout << matr1[i][j] << " ";
}
cout << endl << endl;
}
cout << endl << endl;
}
//Obtener el mayor de la matriz
template<typename T>
T Matriz<T>::mayor()
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if(matr1[i][j] > mayor_){
mayor_ = matr1[i][j];
}
}
}
return mayor_;
}
//Obtener el menor de la matriz
template<typename T>
T Matriz<T>::menor()
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if(matr1[i][j] < menor_){
menor_ = matr1[i][j];
}
}
}
return menor_;
}
//Obtener la moda de la matriz
template<typename T>
T Matriz<T>::moda()
{
//creo una matriz auxiliar
Matriz maux(fils,cols);
//lleno la matriz con ceros
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
maux.matr1[i][j] = 0;
}
}
dim_matriz = fils * cols;
int y=0;//para retener una fila n veces
int z=0;//para retener una columna n veces
//empiezo a comparar cada elemento n veces
for(int x=0;x<dim_matriz;x++){
for (int i = 0; i < fils; i++){
for (int j = 0; j < cols; j++){
if(matr1[y][z] == matr1[i][j]){
maux.matr1[i][j]++;//incremento en 1 el valor de la matriz aux en esa posicion
}
}
}
//pasar a la siguiente columna despues de n comparaciones
z++;
if(z==cols){//empiezo a comparar con la siguiente fila
z=0;//empiezo nuevamente en la 1era columna
y++;//paso a la siguiente fila
}
}
//obtengo el valor mayor de la matriz
mayor_ = maux.mayor();
if(mayor_==1){//si ningun valor se ha repetido mas de una vez no hay moda
return -1;
} else {
for(int i=0; i<fils;i++){
for(int j=0;j<cols;j++){
if(maux.matr1[i][j] == mayor_) {
moda_ = matr1[i][j];
}
}
}
}
return moda_;
}
//Intercambiar dos filas en una matriz
template<typename T>
void Matriz<T>::inter_filas(int fil1, int fil2)
{
if(fil1 > fils || fil2 > fils){
cout << "Por favor, hasta cuando " << endl;
} else {
T temp;
fil1--;
fil2--;
for(int i=0;i<cols;i++){
temp = matr1[fil1][i];
matr1[fil1][i] = matr1[fil2][i];
matr1[fil2][i] = temp;
}
cout << "Se intercambio la fila " << fil1 + 1 << " por la " << fil2 + 1 << endl;
imprimir();
}
}
//Intercambiar dos columnas en una matriz
template<typename T>
void Matriz<T>::inter_cols(int col1, int col2)
{
if(col1 > cols || col2 > cols){
cout << "Por favor, hasta cuando " << endl;
} else{
T temp;
col1--;
col2--;
for(int i=0;i<fils;i++){
temp = matr1[i][col1];
matr1[i][col1] = matr1[i][col2];
matr1[i][col2] = temp;
}
cout << "Se intercambio la columna " << col1 + 1 << " por la " << col2 + 1 << endl;
imprimir();
}
}
//Verificar si una matriz es simetrica
template<typename T>
bool Matriz<T>::esSimetrica()
{
if(fils!=cols) {
return false;
}
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if (matr1[i][j]!=matr1[j][i]){
return false;
}
}
}
return true;
}
//Verificar si una matriz es identidad
template<typename T>
bool Matriz<T>::esIdentidad()
{
if(fils!=cols) {
return false;
}
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
if (i == j) {
if (matr1[i][j] != 1)
return false;
} else {
if (matr1[i][j] != 0)
return false;
}
}
}
return true;
}
//Multiplicar a una matriz por un escalar
template<typename T>
void Matriz<T>::multi_escalar(T escalar)
{
for(int i=0;i<fils;i++){
for(int j=0;j<cols;j++){
matr1[i][j] = matr1[i][j] * escalar;
}
}
cout << "Se multiplico a la matriz por el escalar " << escalar << endl;
imprimir();
}
//Obtener la transpuesta de una matriz
template<typename T>
void Matriz<T>::transpuesta()
{
Matriz matresult(cols,fils);
for(int i=0;i<cols;i++){
for(int j=0;j<fils;j++){
matresult.matr1[i][j]= matr1[j][i];
}
}
matresult.imprimir();
}
//Suma de matrices con sobrecarga de operadores
template<typename T>
Matriz<T> Matriz<T>::operator+ (const Matriz &matr2)
{
Matriz matresult(fils,cols);
for (int i=0;i<fils;i++){
for (int j=0;j<cols;j++){
matresult.matr1[i][j] = matr1[i][j] + matr2.matr1[i][j];
}
}
return matresult;
}
//Resta de matrices con sobrecarga de operadores
template<typename T>
Matriz<T> Matriz<T>::operator- (const Matriz &matr2)
{
Matriz matresult(fils,cols);
for (int i=0;i<fils;i++){
for (int j=0;j<cols;j++){
matresult.matr1[i][j] = matr1[i][j] - matr2.matr1[i][j];
}
}
return matresult;
}
//Multiplicacion de matrices con sobrecarga de operadores
template<typename T>
Matriz<T> Matriz<T>::operator* (const Matriz &matr2)
{
Matriz matresult(fils,matr2.cols);
T total;
for (int i=0;i<fils;i++){
for (int j=0;j<matr2.cols;j++){
for(int k=0;k<cols;k++){
total += (matr1[i][k] * matr2.matr1[k][j]);
//para mostrar lo que pasa
/*cout << "(" << matr1[i][k] << " * " << matr2.matr1[k][j] << ")";
if(k<cols-1){
cout << " + ";
} else {
cout << " = " << total;//despues del ultimo muestro la suma
}*/
}
//cout << endl;
matresult.matr1[i][j] = total;
total = 0;//para limpiar el total sumado arriba
}
cout << endl;
}
return matresult;
}
template<typename T>
void Matriz<T>::eliminar()
{
for(int i=0;i<fils;i++){
delete[] matr1[i];
}
delete[] matr1;
}
template<typename T>
Matriz<T>::~Matriz(){}
main.cpp
#include <iostream>
#include "Matriz.h"
#include "Matriz.cpp"
using namespace std;
int main()
{
srand(time(NULL));//para no generar los mismos numeros aleatorios
int fils,cols,fil1,col1,fil2,col2;
cout << "Ingresa nro de filas " << endl;
cin >> fils;
cout << "Ingresa nro de columnas " << endl;
cin >> cols;
cout << endl;
Matriz<int> a(fils,cols);
Matriz<int> b(fils,cols);
Matriz<int> c(fils,cols);//matriz para almacenar el resultado de las operaciones
a.llenar_aleatorio();//existe el metodo llenar_teclado() para otros tipos
b.llenar_aleatorio();
cout << "Operaciones con matrices " << endl;
cout << "Matriz A " << endl;
a.imprimir();
cout << "Matriz B " << endl;
b.imprimir();
cout << "Matriz A + B " << endl;
c = a + b;
c.imprimir();
cout << "Matriz A - B " << endl;
c = a - b;
c.imprimir();
cout << "Matriz A * B " << endl;
c = a * b;
c.imprimir();
cout << "Operaciones basicas con la matriz A" << endl;
cout << "Matriz A " << endl;
a.imprimir();
cout << "El mayor de la matriz es: " << a.mayor() << endl;
cout << "El menor de la matriz es: " << a.menor() << endl;
cout << "La moda de la matriz es: " << a.moda() << endl;
cout << (a.esSimetrica() ? "" : "No") << " Es simetrica." << endl;
cout << (a.esIdentidad() ? "" : "No") << " Es identidad." << endl;
cout << endl;
cout << "Ingresa el escalar " << endl;
cin >>a.escalar;
a.multi_escalar(a.escalar);
cout << "Intercambio: Ingresa dos filas del 1 al " << fils << endl;
cin >>fil1;
cin >>fil2;
a.inter_filas(fil1,fil2);
cout << "Intercambio: Ingresa dos columnas del 1 al " << cols << endl;
cin >>col1;
cin >>col2;
a.inter_cols(col1,col2);
cout << "Transpuesta de A " << endl;
a.transpuesta();
a.eliminar();
b.eliminar();
c.eliminar();
return 0;
}
Particularmente, todos los ejercicios no son nada difíciles de resolver, pero yo me estanqué en la moda y creo que fue el problema que me hizo pensar un rato.
Lo resolví, pero sinceramente no me siento bien con la solución. No me gustó porque tiene una complejidad de O(n2) y con una matriz muy grande puede tarda mucho debido al número de recorridos y comparaciones.
La solución consistió en:
- Crear otra matriz auxiliar con el mismo nro de filas columas y llenarla con ceros.
- Recorrer la matriz original e ir comparando el primer elemento con todos los otros elementos de la matriz y contar sus repeticiones y así sucesivamente con los demás elementos.
- Si encuentro una repetición, incremento en uno el valor en esa posición de la matriz auxiliar.
- Luego hallar el mayor elemento de la matriz auxiliar.
- Y finalmente recorrer la matriz auxiliar, cuando algún elemento de esta matriz sea igual al mayor elemento, quiere decir, que ese fue el elemento que más se repitió en la matriz original. Por lo tanto la moda se encuentra en esa posición.
Matriz original 17 16 10 26 10 3 9 19 29 7 1 6 6 20 0 10 Matriz auxiliar al inicio 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Matriz auxiliar despues de las comparaciones con el nro de repeticiones de los valores 1 1 3 1 3 1 1 1 1 1 1 2 2 1 1 3
La moda de la matriz es: 10,
3 es el valor maximo que se repite en la matriz
Y en las posiciones en que se encuentra 3 se encuentra 10 en la matriz original.
Un tip que me dió el profe es reducir el nro de comparaciones creando una matriz booleana e ir poniendo unos y ceros a los números que ya comparé para luego no volver a comparar con los números que comparé anteriormente. Voy a seguir resolviendo el problema,si alguien tiene otra solución y puede explicarla fantástico.
Si yu










excelente compadre te pasaste siga asi, a favoritos la web :$ salu2
Buen blog, queria hacer una consulta:
como se podria obtner los sub rectangulos de una matriz y su suma?
osea una suma por cada sub rectangulo.