Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: hackersanfe en 4 Diciembre 2018, 19:10 pm



Título: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: hackersanfe en 4 Diciembre 2018, 19:10 pm
Buenas tardes, estoy intentando realizar esta función en C, sin embargo no se me ocurre la manera correcta de llegar a ella. Concretamente mi ejercicio es:

"Escribe un programa, que en primer lugar, genere una matriz de NxM elementos enteros con números aleatorios comprendidos entre 1 y 20 (N y M constantes enteras globales).
El programa además de generar la matriz, deberá escribir sus valores y escribir un mensaje indicando si hay o no dos columnas iguales en la matriz, en caso de no haberlas, solo en ese caso, deberá escribir un mensaje indicando si hay o no dos filas iguales en la matriz. Si no hubiera ni dos filas iguales, ni dos columnas iguales escribirá un mensaje indicándolo.
También escribirá el valor máximo y la fila y columna en la que se encuentra la primera aparición del valor máximo (haciendo un recorrido por filas)."

Se trata de una función de NxM.
Si me podeis dar una idea de como seria el hacerla me ayudariais un monton. Porque en mi cabeza parece facil (y seguro que lo es) pero no llego a ello... un saludo y gracias por cualquier ayuda recibida.
Código:
#include<stdlib.h>
#include<time.h>
#include <stdio.h>
#define N 3
#define M 6

void escribirMat (int mat[N][M]);
void generaMat (int mat[N][M]);
void matrizMaxPos (int mat[N][M], int *max, int *fil, int *col);
int columnasIguales(int mat[N][M]);


int main()
{
    int mat[N][M];
    int *max=0,*fila=0,*columna=0;
    generaMat(mat);
    escribirMat(mat);
    matrizMaxPos(mat,&max,&fila,&columna);
    printf("\nMaximo: %d y aparece por primera vez en la fila %d y columna %d.\n",max,fila,columna);
    if(columnasIguales(mat)==1){
        printf("\nHay al menos dos columnas iguales.\n");
    }
    else printf("\nNinguna columna igual.\n");
    return 0;
}


void generaMat(int mat[N][M])
{
    int f,c;
    srand(time(NULL));
    for(f=0; f<N; f++)
        for(c=0; c<M; c++)
            mat[f][c]=rand()%20+1;
}

void matrizMaxPos (int mat[N][M], int *max, int *fil, int *col){
    int i,j,enc=0;
    for(i=0;i<N;i++){
        for(j=0;j<M;j++){
            if(*max<mat[i][j])
                *max=mat[i][j];
        }
    }
    for(i=0;i<N;i++){
        for(j=0;j<M;j++){
            if(*max==mat[i][j]&&!enc){
                *fil=i+1;
                *col=j+1;
                enc=1;
            }
        }
    }
}

int columnasIguales(int mat[N][M]){
    int i=0,j=0,iguales=0;
    if((mat[i][j]==mat[i][j+1]&&i<N-1&&j<M-1)&&(mat[i+1][j]==mat[i+1][j+1]&&i<N-1&&j<M-1)&&(mat[i+2][j]==mat[i+2][j+1]&&i<N-1&&j<M-1))
        iguales=1;
    else{
        i++;
        j++;
    }
    return iguales;
}

void escribirMat (int mat[N][M]){
    int i,j;
    for(i=0;i<N;i++){
        for(j=0;j<M;j++){
            printf("%d ", mat[i][j]);
        }
        printf("\n");
    }
}


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: K-YreX en 4 Diciembre 2018, 19:14 pm
Especifica qué parte es la que no sabes implementar... si es desde meter los valores en la matriz o comparar dos filas o columnas...
Y si tienes algo de código hecho ponlo también en el mensaje para que lo veamos. :-X


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: hackersanfe en 4 Diciembre 2018, 19:28 pm
Especifica qué parte es la que no sabes implementar... si es desde meter los valores en la matriz o comparar dos filas o columnas...
Y si tienes algo de código hecho ponlo también en el mensaje para que lo veamos. :-X
Ya está compañero.
Especificamente lo que no se implementar es la comparacion de la primera columna con la segunda, la primera con la tercera, la primera con la cuarta... hasta que se hayan comparado todas con todas. La funcion que aparece ahi de columnas iguales no me funciona por cierto, es lo que intente yo pero nada.


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: K-YreX en 4 Diciembre 2018, 20:28 pm
Primero tienes que cambiar la declaración siguiente:
Código
  1. int *max=0,*fila=0,*columna=0;
No tienes que declararlos como punteros si luego los pasas a la función usando "&".

Ahora la función, por ejemplo una forma de comparar cada columna de una forma visual es la siguiente:
Código
  1. int compararColumnas(int matriz[FILAS][COLUMNAS]){
  2. int iguales = 0;
  3. int columnaAComparar[FILAS];
  4.  
  5. for(int i = 0; i < COLUMNAS-1 && !iguales; i++){
  6. for(int j = 0; j < FILAS; j++) // copiamos la columna a comparar en columnaAComparar
  7. columnaAComparar[j] = matriz[j][i];
  8.  
  9. for(int m = i+1; m < COLUMNAS && !iguales; m++){ // para cada columna en adelante, mientras no sean iguales...
  10. iguales = 1; // ...suponemos que la columna m es igual a la columna i guardada en columnaAComparar
  11. for(int n = 0; n < FILAS && iguales; n++) // recorremos la columna m mientras no lleguemos al final y sean iguales
  12. if(matriz[n][m] != columnaAComparar[n])
  13. iguales = 0;
  14. }
  15. }
  16. return iguales;
  17. }

También puedes ahorrarte el copiar la columna a comparar en cada iteración. Así ganas eficiencia aunque se ve peor por eso para que lo veas bien te lo dejo así y ya tú cuando lo entiendas puedes cambiarlo para no tener que usar un array auxiliar. Suerte.


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: hackersanfe en 4 Diciembre 2018, 23:55 pm
Muchisimas gracias, la verdad es que aunque exista otra manera mas eficiente de hacerla, esa me parece clarisima. Gracias de verdad. ;-)


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: CalgaryCorpus en 5 Diciembre 2018, 02:05 am
Me gusto la solucion propuesta.

Mientras la miraba se me ocurrio otra, pero es definitivamente mas complicada, asi que la presento solo para incluir una idea adicional.

Si uno mantiene adicionalmente algun valor para cada columna / fila (por ejemplo la suma de los elementos), se puede descartar rapidamente si una fila es candidata a ser igual a otra.

Código:
  1   2   3  4
  4   5   6  8
  7   8   9  0
[12  15  18  12]  <-- sumas


Solo es necesario comparar la 1a y 4ta columna.
Lo que significa para el codigo propuesto es hacer 1 comparacion que controle si hay que hacer el ciclo for de la linea 11 o no.

La modificacion es, en la linea 10, cambiar la asignacion y hacer:
Código
  1.             iguales = (sumas[i] == sumas[m]);

El arreglo sumas se crea en generaMat.



Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: hackersanfe en 5 Diciembre 2018, 18:58 pm
Me gusto la solucion propuesta.

Mientras la miraba se me ocurrio otra, pero es definitivamente mas complicada, asi que la presento solo para incluir una idea adicional.

Si uno mantiene adicionalmente algun valor para cada columna / fila (por ejemplo la suma de los elementos), se puede descartar rapidamente si una fila es candidata a ser igual a otra.

Código:
  1   2   3  4
  4   5   6  8
  7   8   9  0
[12  15  18  12]  <-- sumas


Solo es necesario comparar la 1a y 4ta columna.
Lo que significa para el codigo propuesto es hacer 1 comparacion que controle si hay que hacer el ciclo for de la linea 11 o no.

La modificacion es, en la linea 10, cambiar la asignacion y hacer:
Código
  1.             iguales = (sumas[i] == sumas[m]);

El arreglo sumas se crea en generaMat.


Claro, es una implementacion un poco mas complicada en mi opinion, pero tambien seria valida.
Ahora estoy intentando hacer que me funcione el modelo que paso el compañero para que haga lo mismo con las filas, de momento no lo estoy consiguiendo, esto es lo que he hecho:
Código:
int compararFilas(int mat[N][M])
{
    int iguales=0,i,j,m,n;
    int filaAComparar[N];
    for(i=0; i<N-1&&!iguales; i++)
    {
        for(j=0; j<M; j++)
            filaAComparar[j]=mat[j][i];

        for(m=i+1; m<M; m++)
       {
            iguales=1;
            for(n=0; n<N&&iguales; n++) /
                if(mat[n][m]!=filaAComparar[n])
                    iguales=0;
        }


    }
    return iguales;
}


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: K-YreX en 5 Diciembre 2018, 19:19 pm
Tienes que ver qué índice representa a las filas y qué índice a las columnas. No vale eso de coger un código cambiarle el nombre y que haga otra cosa.
Edit: Además mira a ver cuál debería ser el tamaño de tu array auxiliar... Suerte.


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: CalgaryCorpus en 5 Diciembre 2018, 19:36 pm
Parece que la logica original hay que modifcarla un poco, pues si existen 2 coliumnas iguales, pero justo las ultimas 2 que se comparan no son iguales, la funcion va a retornar 0.

Es lo que se quiere?


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: K-YreX en 5 Diciembre 2018, 19:44 pm
Parece que la logica original hay que modifcarla un poco, pues si existen 2 coliumnas iguales, pero justo las ultimas 2 que se comparan no son iguales, la funcion va a retornar 0.

Es lo que se quiere?

Es cierto, faltaría meterle la condición de que no sean iguales a uno de los <for> para que en cuanto haya dos iguales salga del todo. Fallo mío :-X Con estas correcciones ya debería funcionar. :silbar:
Edit: Ya está modificado el código original (creo que no tiene más fallos, si alguien encuentra alguno que me lo comente). Y Hackersanfe, te recomiendo que lo pienses por ti mismo, el reto está en conseguir hacerlo funcionar sin mirar la solución, mirándola es muy fácil.


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: hackersanfe en 8 Diciembre 2018, 11:32 am
Lo sigo intentando y nada :( solo dime, asi esta bien para que te almacene los valores de la primera fila en un vector verdad?
Código:
    for(i=0;i<N&&!iguales;i++)
        for(j=0;j<M;j++)
            filaAComparar[j]=mat[i][j];
Es que no se que puede ser lo que escriba mal porque en mi cabeza pienso que esta bien
Edito: parece que ahora ya lo voy consiguiendo, os informo
Edito2: conseguido! muchisimas gracias por la ayuda, nada mejor que hacerse el programa a papel y boli... jeje
Edito3: Pues no, me funciona en algunos casos y otros no, no se que puedo tener mal...
Código:
int compararFilas(int mat[N][M],int v[M])
{
    int iguales=0,i,j,m,n;
    for(i=0; i<N&&!iguales; i++)
    {
        for(j=0; j<M; j++)
        {
            v[j]=mat[i][j];
        }

        for(m=0; m<M&&!iguales; m++)
        {
            iguales=1;
            for(n=i+1; n<N&&iguales; n++)
            {
                if(mat[n][m]!=v[m])
                    iguales=0;
            }
        }
    }
    return iguales;
}


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: K-YreX en 8 Diciembre 2018, 15:04 pm
Hay que darle la vuelta a la segunda parte:
Código
  1. int compararFilas(matriz[FILAS][COLUMNAS]){
  2.    int filaAComparar[COLUMNAS];
  3.    int iguales = 0;
  4.    for(int i = 0; i < FILAS - 1 && !iguales; i++){
  5.        for(int j = 0; j < COLUMNAS; j++)
  6.            filaAComparar[j] = matriz[i][j];
  7.  
  8.        for(int m = i+1; m < FILAS && !iguales; m++){
  9.            iguales = 1;
  10.            for(int n = 0; n < COLUMNAS && iguales; n++)
  11.                if(filaAComparar[n] != matriz[m][n])
  12.                    iguales = 0;
  13.        }
  14.    }
  15.    return iguales;
  16. }

Si no me he equivocado esa función debería funcionar. Primero, la <i> tiene que ir hasta hasta la penúltima fila ya que no tiene sentido comparar la última con la siguiente (porque no hay siguiente).
Además el array auxiliar no hace falta pasarlo como parámetro, puede ser una variable local que "desaparezca" en cuanto acabe la función.
En la parte final el bucle exterior empieza en <i+1> y el interior en 0. Esto se traduce como: "para cada fila posterior a la fila <i> recorremos toda la fila". Si le das la vuelta fíjate que en el <if> usas <v[m]> y <m> en tu caso no va de 0 a COLUMNAS-1. En tu caso <m> se queda con un valor fijo y lo que se mueve es la <n>. Siempre varía más veces el valor del bucle interior que el exterior. Suerte. :-X


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: MAFUS en 8 Diciembre 2018, 17:40 pm
Supongo que con este te irá bien.
Va comprobando desde la primera hasta la penúltima columna si las siguientes son iguales a ellas. En cuánto detecta que dos elementos no son iguales va no pierde más tiempo y va a buscar la siguiente columna. Si detecta que dos columnas son iguales se detiene e informa de ello.
Hay que usar stdbool, pero se puede cambiar el bool por int y true y false por 1 y 0 respectivamente.

Código
  1. bool columnas_iguales(int matriz[][COLUMNAS]) {
  2.    bool retval = false;
  3.  
  4.    for(int i=0; !retval && i<COLUMNAS-1; ++i) {
  5.        for(int j=i+1; !retval && j<COLUMNAS; ++j) {
  6.            int m;
  7.            for(m=0; m<FILAS; ++m) {
  8.                if(matriz[m][i]!=matriz[m][j])
  9.                    break;
  10.            }
  11.            if(m==FILAS)
  12.                retval = true;
  13.        }
  14.    }
  15.  
  16.    return retval;
  17. }


Título: Re: Función que diga si dos columnas/filas de una matriz son iguales.
Publicado por: K-YreX en 8 Diciembre 2018, 22:06 pm
Supongo que con este te irá bien.
Va comprobando desde la primera hasta la penúltima columna si las siguientes son iguales a ellas. En cuánto detecta que dos elementos no son iguales va no pierde más tiempo y va a buscar la siguiente columna. Si detecta que dos columnas son iguales se detiene e informa de ello.
Hay que usar stdbool, pero se puede cambiar el bool por int y true y false por 1 y 0 respectivamente.

Código
  1. bool columnas_iguales(int matriz[][COLUMNAS]) {
  2.    bool retval = false;
  3.  
  4.    for(int i=0; !retval && i<COLUMNAS-1; ++i) {
  5.        for(int j=i+1; !retval && j<COLUMNAS; ++j) {
  6.            int m;
  7.            for(m=0; m<FILAS; ++m) {
  8.                if(matriz[m][i]!=matriz[m][j])
  9.                    break;
  10.            }
  11.            if(m==FILAS)
  12.                retval = true;
  13.        }
  14.    }
  15.  
  16.    return retval;
  17. }

Por lo que yo tengo entendido no es muy recomendable usar instrucciones como <break> (excepto en un <switch>), <goto>, etc. Entonces se puede conseguir lo mismo usando la propia variable <retval>. Supones que son iguales y cuando dos valores no coincidan, dejan de ser iguales. Quedaría así:
Código
  1. bool columnas_iguales(int matriz[][COLUMNAS]) {
  2.    bool retval = false;
  3.    for(int i=0; !retval && i<COLUMNAS-1; ++i) {
  4.        for(int j=i+1; !retval && j<COLUMNAS; ++j) {
  5.            retval = true;
  6.            for(int m=0; retval && m<FILAS; ++m)
  7.                if(matriz[m][i]!=matriz[m][j])
  8.                    retval = false;
  9.    }
  10.    return retval;
  11. }
A esto me refería cuando al principio le comenté a Hackersanfe que intentará hacerlo sin el array auxiliar.

PD: No sabía que para usar el tipo de dato <bool> en C se podía hacer con <stdbool>. Yo creaba una enumeración para poder usarlo. Algo así:
Código
  1. typedef enum {false, true} bool;