Credo di sì, anch'io ho fatto così, anche se come al solito alla mia maniera cervellotica.
Lo schema generale che ho seguito è:
alloca_matrice
popola_matrice
mostra_matrice
rileva_colonne_crescenti
mostra_indici (delle colonne con valori crescenti)
fondi_colonne_crescenti
mostra_vettore_fusione
Con tutti gli arzigogoli dovuti al fatto che ho usato la memoria dinamica e che son solito verificare più condizioni di errore possibile, sviluppare tutto ha richiesto questa bella pappardella, neppure particolarmente ordinata (ricordati che non sono un programmatore ma un hobbista):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_VALORE 100 // la gamma dei valori impiegati va da 0 a 100
#define DIFF_MIN 10 // il valore di riferimento per valutare la " distanza"
#define Q_RIGHE 4 // la quantita' delle righe nella matrice
#define Q_COLONNE 15 // la quantita' delle colonne nella matrice
int alloca_matrice( int ***pm, size_t qr, size_t qc );
void libera_matrice( int ***m, size_t qr );
int popola_matrice( int **m, size_t qr, size_t qc );
int rileva_colonne_crescenti( int **m, size_t qr, size_t qc,
int **colCresc, size_t *qColCresc );
int fondi_colonne_crescenti( int **m, size_t qr, size_t qc,
int *cc, size_t qcc, int k,
int **vf, size_t *qElVf );
int mostra_matrice( int **m, size_t qr, size_t qc );
int mostra_indici( int *pi, size_t qc, size_t qi );
int mostra_vettore_fusione( int *v, size_t qEl, int diff );
int altra_matrice( void );
int main() {
int **m = NULL; // la matrice
int k = DIFF_MIN; // la "distanza"
if( alloca_matrice(&m,Q_RIGHE,Q_COLONNE) ) {
do {
int *colCresc = NULL;
size_t qColCresc = 0;
popola_matrice( m, Q_RIGHE, Q_COLONNE );
mostra_matrice( m, Q_RIGHE, Q_COLONNE );
if( rileva_colonne_crescenti(m,Q_RIGHE,Q_COLONNE,&colCresc,&qColCresc) ) {
mostra_indici( colCresc, Q_COLONNE, qColCresc );
if( qColCresc > 1 ) {
int ok, *vettFus = NULL;
size_t qElVettFus = 0;
ok = fondi_colonne_crescenti( m, Q_RIGHE,Q_COLONNE,
colCresc, qColCresc, k,
&vettFus, &qElVettFus );
if( ok ) {
mostra_vettore_fusione( vettFus, qElVettFus, k );
free( vettFus );
}
else {
printf( "Errore nel fondere le colonne crescenti.\n\n" );
}
}
if( colCresc ) free( colCresc );
}
else {
printf( "Errore nel rilevare le colonne crescenti.\n\n" );
}
} while( altra_matrice() );
libera_matrice( &m, Q_RIGHE );
}
else {
printf( "Errore nell'allocare la matrice.\n\n" );
}
return 0;
}
// pm = puntatore a matrice; qr = quantita righe; qc = quantita colonne
int alloca_matrice( int ***pm, size_t qr, size_t qc ) {
int ok = 0;
if( pm ) {
int **m = calloc( qr, sizeof(*m) );
if( m ) {
size_t r;
for( r=0; r<qr; ++r ) {
m[r] = calloc( qc, sizeof(*m) );
if( NULL == m[r] ) break;
}
ok = r==qr;
if( !ok ) libera_matrice( pm, r );
}
*pm = m;
}
return ok;
}
// m = matrice; qr = quantita righe
void libera_matrice( int ***pm, size_t qr ) {
if( pm ) {
int **m = *pm;
size_t r;
for( r=0; r<qr; ++r )
m[r] = m[r] ? free(m[r]), NULL : NULL;
free( m );
m = NULL;
*pm = m;
}
}
/*==============================================================================
Immette nella matrice m valori casuali compresi tra 0 e MAX_VALORE (inclusi).
==============================================================================*/
int popola_matrice( int **m, size_t qr, size_t qc ) {
// m = matrice; qr = quantita righe; qc = quantita colonne
int ok = 0;
if( m ) {
size_t r, c;
srand( time(NULL) );
for( r=0; r<qr; ++r ) {
if( m[r] ) {
for( c=0; c<qc; ++c ) {
// tra 0 e MAX_VALORE inclusi
m[r][c] = rand()%(MAX_VALORE+1);
}
}
else {
break;
}
}
ok = r==qr;
}
return ok;
}
/*==============================================================================
Analizza la matrice m in cerca delle colonne contenenti valori crescenti.
In uscita, immette 1 in ciascuno degli elementi del vettore colCresc che
corrisponde ad una delle colonne che contengono valori crescenti, zero in tutti
gli altri.
Immette in qColCresc la quantita' delle colonne crescenti rilevate.
Il vettore colCresc viene allocato dinamicamente, ed e' responsabilita' del
chiamante liberare la memoria allocata.
==============================================================================*/
int rileva_colonne_crescenti( int **m, size_t qr, size_t qc,
int **colCresc, size_t *qColCresc ) {
// m = matrice; qr = quantita righe; qc = quantita colonne
// colCresc=flags colonne crescenti; qColCresc=quantita' delle colonne crescenti
int ok = 0;
if( m && colCresc && qColCresc ) {
int *i = NULL;
size_t r;
for( r=0; r<qr; ++r ) if( !m[r] ) break;
if( r<qr ) return 0; // errore, righe non valide
i = calloc( qc, sizeof(*i) );
if( i ) {
size_t qi, c;
for( qi=0, c=0; c<qc; ++c ) {
for( r=0; r<qr-1; ++r ) {
if( m[r][c] >= m[r+1][c] ) break;
}
i[c] = r == qr-1;
qi += i[c];
}
*colCresc = i;
*qColCresc = qi;
ok = 1;
}
}
return ok;
}
/*==============================================================================
Usata in qsort() per ordinare vettori di interi.
==============================================================================*/
int confronta_int( const void *p1, const void *p2 ) {
int i1 = *((int*)p1);
int i2 = *((int*)p2);
return i1!=i2 ? (i1>i2?1:-1) : 0;
}
/*==============================================================================
Elimina dal vettore v di qEl elementi tutti quegli elementi la differenza tra i
quali e' minore di diff.
==============================================================================*/
size_t distanzia_elementi_vettore( int *v, size_t qEl, int diff ) {
size_t i=0, j=1;
while( j < qEl ) {
while( v[j]-v[i]<diff && j<qEl ) ++j;
if( j!=qEl ) v[++i] = v[j++];
}
return i+1;
}
/*==============================================================================
Copia in un unico vettore vf tutte le colonne della matrice m che sono
costituite esclusivamente da valori progressivamente crescenti.
Ordina il vettore ottenuto.
Elimina dal vettore (usando distanzia_elementi_vettore()) tutti quegli elementi
la differenza tra i quali e' minore di diff.
In uscita, vf contiene il puntatore al vettore elaborato e qElVf la quantita'
degli elementi contenuti nel vettore stesso.
Dal momento che il vettore e' allocato dinamicamente, spetta al chiamante
liberare la memoria allocata.
==============================================================================*/
int fondi_colonne_crescenti( int **m, size_t qr, size_t qc,
int *cc, size_t qcc, int k,
int **vf, size_t *qElVf ) {
// m = matrice; qr = quantita righe; qc = quantita colonne
// cc = colonne crescenti; qcc = quantita' delle colonne crescenti
// k = differenza minima tra i valori delle colonne crescenti
// vf = vettore fusione; qElVf = quantita' degli elementi in vf
int ok = 0;
if( m && cc && vf && qElVf ) {
*vf = calloc( qcc*qr, sizeof(**vf) );
*qElVf = 0;
if( *vf ) {
size_t r, c, i, j;
for( i=0, j=0, c=0; c<qc&&j<qcc; ++c ) {
if( cc[c] ) {
for( r=0; r<qr; ++r, ++i )
(*vf)[i] = m[r][c];
++j;
}
}
qsort( *vf, qcc*qr, sizeof(**vf), confronta_int );
*qElVf = distanzia_elementi_vettore( *vf, j*qr, k );
ok = 1;
}
}
return ok;
}
/*==============================================================================
Dato un valore intero senza segno, restituisce la quantita' di cifre necessarie,
nella base di numerazione specificata, per esprimerlo come stringa.
==============================================================================*/
size_t calcola_quantita_cifre( size_t numero, size_t base ) {
size_t qc = 1; // "qc" = quantita' delle cifre
while( numero /= base ) ++qc;
return qc;
}
/*==============================================================================
Predispone la stringa di formato necessaria a mostra_matrice() per visualizzare
i valori della matrice.
==============================================================================*/
void predisponi_formato( char *strFrmt ) {
size_t qc = calcola_quantita_cifre( MAX_VALORE, 10 );
sprintf( strFrmt, "%%%dd%%c", qc );
}
int mostra_matrice( int **m, size_t qr, size_t qc ) {
// m = matrice; qr = quantita righe; qc = quantita colonne
int ok = 0;
if( m ) {
char frmt[16];
size_t r, c;
printf( "Matrice:\n" );
predisponi_formato( frmt );
for( r=0; r<qr; ++r ) {
if( m[r] ) {
for( c=0; c<qc; ++c ) {
printf( frmt, m[r][c], c<qc-1?' ':'\n' );
}
}
else {
printf( "riga nulla\n" );
}
}
ok = 1;
}
return ok;
}
/*==============================================================================
Visualizza in console gli indici delle colonne che contengono esclusivamente
valori in ordine crescente.
==============================================================================*/
int mostra_indici( int *pi, size_t qc, size_t qi ) {
// pi: puntatore al vettore dei flag che individuano le colonne crescenti
// qc: quantita' colonne nella matrice, qi: quantita' indici nel vettore
int ok = 0;
if( pi ) {
if( qi > 0 ) {
size_t i, c;
printf( "\n%u colonn%c con valori crescenti a%sindic%c",
qi, qi>1?'e':'a', qi>1?"gli ":"ll'", qi>1?'i':'e' );
for( i=0, c=0; c<qc; ++c )
if( pi[c] ) printf( " %d%c", c, i++<qi-1?',':'.' );
printf( "\n\n" );
}
else {
printf( "\nNessuna colonna con valori crescenti.\n\n" );
}
ok = 1;
}
return ok;
}
/*==============================================================================
Visualizza in console il vettore predisposto da fondi_colonne_crescenti().
==============================================================================*/
int mostra_vettore_fusione( int *v, size_t qEl, int diff ) {
// v = il vettore; qEl = la quantita' degli elementi nel vettore
int ok = 0;
if( v ) {
if( qEl > 0 ) {
size_t i;
printf( "%d valori con differenza maggiore di %d:\n ", qEl, diff );
for( i=0; i<qEl; ++i )
printf( " %d%c", v[i], i<qEl-1?',':'.' );
printf( "\n\n" );
}
else {
printf( "Nessun valore con differenza maggiore di %d.\n\n", diff );
}
ok = 1;
}
return ok;
}
/*==============================================================================
Chiede all'utente se desidera lasciare il programma o procedere con
l'elaborazione di una nuova matrice.
==============================================================================*/
int altra_matrice( void ) {
do {
int c;
printf( "\"Invio\" per valutare un'altra matrice, \"Q\" per uscire... " );
c = getchar();
if( c == '\n' ) {
system( "cls" );
return 1;
}
else {
while( getchar() != '\n' );
if( c == 'q' || c == 'Q' )
return 0;
}
} while( 1 );
}