Domanda Risolto Stampa matrice concentrica

Stato
Discussione chiusa ad ulteriori risposte.

Showme

Utente Silver
26 Settembre 2017
112
18
23
59
Salve ragazzi, vorrei creare un programma che presa in input una matrice, stampi i suoi valori/caratteri visitandoli in modo concentrico, nel senso:
presa in esempio una matrice 3x3 cosi definita {1,2,3-- 4,5 6-- 7 ,8, 9}, stampi 1 2 3 6 9 8 7 4 5.
Ho provato a creare qualche ciclo ma nulla... qualcuno saprebbe darmi qualche consiglio?
Grazie in anticipo :D
 
Beh, inizia a postare qualcosa almeno non siamo noi a fare tutto il lavoro al posto tuo.
Posta il tuo tentativo sbagliato, oppure prova a fare qualcosa di un po' più semplice... per esempio, saresti capace di scrivere un codice che stampa solo il quadrato esterno? Per rimandarci al tuo esempio: 1 2 3 6 9 8 7 4. Se sei capace di farlo poi possiamo vedere come modificarlo per fare quello che richiedi.
 
Si scusami... non voglio assolutamente che voi facciate tutto il lavoro al posto mio sennò non avrebbe senso perché non imparerei nulla, non avevo postato il codice precedente perché non riuscendo a farlo lo stavo facendo con 10 cicli tutti a mano..., comunque ho provato a fare quello della cornice esterna e funziona ma mi sembra un po troppo macchinoso dimmi che ne pensi.

C++:
#include <iostream>

using namespace std;

bool cerca_numero(int grandezza,int *matrice, int ricercato)
{
    bool risposta = false;

    int i=0;
    while(i<grandezza)
    {
        if (matrice[i] == ricercato)
        {
            risposta = true;
        }
        else
        {

        }
        i++;
    }
    return risposta;
}


int main()
{
    int righe;
    int colonne;

    cout << "Inserisci il numero di righe:" << endl;
    cin >> righe;
    cout << "Inserisci il numero di colonne:" << endl;
    cin >> colonne;

    int matrice[righe][colonne];
    int grandezza = righe*colonne;

    cout << "Inserisci i " << grandezza << " numeri nella matrice" << endl;

    int i=0;
    while(i<righe)
    {
        int j=0;
        while(j<colonne)
        {
            int numero;
            cin >> numero;
            matrice[i][j]=numero;
            j++;
        }
        i++;
    }

    cout << "La matrice e': " << endl;

    i=0;
    while(i<righe)
    {
        int j=0;
        while(j<colonne)
        {
            cout << matrice[i][j] << " ";
            j++;
        }
        cout << endl;
        i++;
    }

    //============ Cerco un numero ================

    int ricercato;

    cout << "Inserisci un numero da cercare nella matrice" << endl;
    cin >> ricercato;
    if(cerca_numero(grandezza, &matrice[0][0], ricercato))
    {
        cout << "Trovato" << endl;
    }
    else
    {
        cout << "Il numero non e' presente" << endl;
    }

    //=========== Stampo la matrice concentrica =========

        i=0;
        int j=0;\
        while(j<colonne)
        {
            cout << matrice[i][j] << " ";
            j++;
        }
        i=1;
        j=colonne-1;
        while(i<righe)
        {
            cout << matrice[i][j] << " ";
            i++;
        }
        j--;
        i--;
        while(j>0)
        {
            cout << matrice[i][j] << " ";
            j--;
        }
        while(i>0)
        {
            cout << matrice[i][j] << " ";
            i--;
        }




    return 0;
}
 
Ultima modifica:
Sì, fa un po' schifo... ma il codice è tuo, quindi io lo tengo buono e ti propongo questo cambiamento:
C++:
for (int k = 0; 2*k < colonne && 2*k < righe; k++) {
    i=0;                                         
    int j=0;                                     
    while(k+j<colonne-k)                         
    {                                            
        cout << matrice[k+i][k+j] << " ";        
        j++;                                     
    }                                            
    i=1+k;                                         
    j=colonne-1-k;                                 
    while(k+i<righe-k)                           
    {                                            
        cout << matrice[k+i][k+j] << " ";        
        i++;                                     
    }                                            
    j--;                                         
    i--;                                         
    while(j-k>0+k)                               
    {                                            
        cout << matrice[k+i][k+j] << " ";        
        j--;                                     
    }                                            
    while(i-k>0+k)                               
    {                                            
        cout << matrice[k+i][k+j] << " ";        
        i--;                                     
    }                                            
}

Ho soltanto introdotto il ciclo for e la variabile k, tutto il resto è esattamente quello che avevi prima. Non l'ho testato a fondo, quindi controlla bene se funziona tutto... poi puoi iniziare a migliorarlo trasformando i tuoi while in for. Il passaggio alla rovescia (i while con il decremento) lo puoi fare usando due for: uno che parte da righe-1 e uno che parte da colonne-1. Vedrai che anche solo con questo il tuo codice migliorerà notevolmente.
 
  • Love
  • Mi piace
Reazioni: Valley e Versus_
Ho provato il codice che mi hai suggerito e andava bene per le 2x2 e per le 3x3, ma aveva un problema con le matrici superiori al 3x3, quindi ho provato ad aggiustarlo e adesso funziona anche con le 5x5, però presenta un problema alla fine.
C++:
for (int k = 0; 2*k < colonne && 2*k < righe; k++) {
        i=0;
        int j=0;
        while(k+j<colonne-k)
        {
            cout << matrice[k+i][k+j] << " ";
            j++;
        }
        i=1+k;
        j=colonne-1-k;
        while(i<righe-k)
        {
            cout << matrice[i][j] << " ";
            i++;
        }
        j--;
        i--;
        while(j>0)   //Il problema è qui, perché nell'ultimo giro di k mi entra pure in questo ciclo
        {
            cout << matrice[i][j] << " ";
            j--;
        }
        j=j+k;
        i=i-k;
        while(i>0+k)
        {
            cout << matrice[i][j] << " ";
            i--;
        }
    }

Dopo aver stampato tutti i valori me ne stampa uno in più che deriva dalla riga che ho commentato, potresti darmi qualche consiglio su come aggiustarlo? Perché questo problema me lo da solo con le 5x5
 
Fai le modifiche che ti ho chiesto di fare... se fai 4 for invece che 4 while diventa molto più semplice capire cosa va storto. La cosa importante, che differisce rispetto alla tua soluzione, è che i 4 cicli for devono essere indipendenti tra loro: adesso il secondo e il terzo while condividono il valore di i e j, con i for dovrai cercare di non farlo. L'idea è che i 4 for dovranno essere quasi identici e, soprattutto, dovranno avere un comportamento consistente; se poi non riesci ti passo io la soluzione, ma vedrai che è più facile usare i for che i while.
Se preferisci cancella il for esterno che ti ho messo io e fai soltanto il quadrante esterno, poi ti spiego come fixxare tutto.
 
  • Mi piace
Reazioni: Showme
Avevi assolutamente ragione... lo ho rifatto usando i for e non ho nemmeno dovuto guardare il codice precedente o il tuo e mi è riuscito al primo tentativo....
C++:
 for(int k=0; 2*k < colonne && 2*k < righe; k++)
    {
        for(int j=0+k; j < colonne-k; j++)
        {
            int i=0+k;
            cout << matrice[i][j] << " ";
        }
        for(int i=1+k; i < righe-k; i++)
        {
            int j=colonne-1-k;
            cout << matrice[i][j] << " ";
        }
        for(int j=colonne-2-k; j > 0+k; j--)
        {
            int i=righe-1-k;
            cout << matrice[i][j] << " ";
        }
        for(int i=righe-1-k; i>0+k; i--)
        {
            int j=0+k;
            cout << matrice[i][j] << " ";
        }
    }

Grazie :D
 
Ultima modifica:
giusto per mio divertimento mi sono voluto auto-sifdare (stile Barney Stinson) nello scrivere del codice generico in grado di printare una matrice come vorresti printarla tu (descritto da te come concentricamente) indipendentemente dalle dimensioni della matrice (sia quadrata che rettangolare) ..
ho usato la OOP per comodità.

te lo mando nel caso potesse interessarti (sfida vinta :asd:)

C++:
#include <cstdio>

#define IS_PAIR(element) ((element+1)/2 == element/2)

class PrintableMatrix
{
public:
    PrintableMatrix(int* pInfo , int rows, int fields)
    {
        m_pInfo = pInfo;
        m_row_num = rows;
        m_field_num = fields;
        m_necessary_cicle = rows*2 -1;
    }


    const bool isIncremental(int iArgument)
    {
        if(IS_PAIR(iArgument))
        {
            if(iArgument == 0)
                return true;
              
            return (iArgument%4 == 0);
        }
      
      
        else
        {
            return isIncremental(--iArgument);
        }
    }

    const int getLimit(int iArgument)
    {
        if(isIncremental(iArgument))
        {
            if(IS_PAIR(iArgument))
                return(m_field_num - (++iArgument/4));
          
            else
                return(m_row_num- (++iArgument/4));
          
        }
      
        else
        {
            return -1 + (++iArgument/4);
        }
    }
  
    const int getInitial(int iArgument)
    {
        if(iArgument == 0)
            return 0;
      
        else
        {
            int ex = getOtherIndex(iArgument-1);
          
            if(isIncremental(iArgument))
                ex++;
              
            else
                ex--;
              
            return ex;
        }
    }
  
    const int getOtherIndex(int iArgument)
    {
        if(0 == iArgument)
            return 0;
          
        int ex = getLimit(iArgument-1);
      
        if(isIncremental(iArgument-1))
            ex--;
      
        else
            ex++;
          
        return ex;
      
    }
  
    void changeValue(int iArgument , int* pValue)
    {
        if(isIncremental(iArgument))
            (*pValue)++;
          
        else
            (*pValue)--;
    }
  
    void printMe()
    {
        for(int i = 0; i <= m_necessary_cicle ; i++)
        {
            const int initial = getInitial(i);
            const int limit = getLimit(i);
            const int otherIndex = getOtherIndex(i);
          
            const bool isPair = IS_PAIR(i);
          
            //printf("log info : initial[%d] , limit[%d] , i[%d] , otherIndex[%d] isPair[%s]\n",initial,limit,i,otherIndex,isPair?"true":"false");
          
            for(int idx = initial ; idx != limit ; )
            {
                int* info = 0;
              
                if(isPair)
                {
                    info = m_pInfo + (otherIndex*m_field_num) + idx;
                }
              
                else
                {
                    info = m_pInfo + (idx*m_field_num) + otherIndex;
                }
              
                printf("value[%d]\n",*info);
                changeValue(i,&idx);
            }
            printf("\n------------------------------------------\n");
        }
    }
  
  
private:
    int* m_pInfo;
    int    m_row_num;
    int m_field_num;
    int m_necessary_cicle;
  
};

int main()
{
    int matrix[4][4] =
    {
        {0,1,2,3},
        {4,5,6,7},
        {8,9,10,11},
        {12,13,14,15},
    };
  
    PrintableMatrix printMatrix(&matrix[0][0],4,4); //address first element,rows-num,fields-num
    printMatrix.printMe();
    return 0;
}

ho dovuto farci un minimo di calcolo matematico prima , ed è venuta fuori una cosa interessante.. nelle formule puoi notare che ho tranquillamente hardcodato il 4 perchè questo numero è fondamentale nei conteggi , altri non è che il numero di lati (sempre 4 sia per matrici quadrate che rettangolari).
mi ha appasionato la cosa si vede? :matto:
 
  • Mi piace
Reazioni: Valley
indipendentemente dalle dimensioni della matrice (sia quadrata che rettangolare)
Secondo me ti sei complicato un po' la vita con quel codice... quello postato da Showme, se fosse del tutto corretto, gestirebbe senza alcun problema anche le matrici rettangolari. Eccone una dimostrazione:
C++:
void print_spiral(int *matrix, int rows, int cols) {
    int min = rows > cols ? cols : rows;

    for (int k = 0; 2*k < min; k++) {
        if (k == cols-k-1 && k == rows-k-1)
            cout << matrix[k*cols+k] << " ";

        for (int i = k; i < cols-k-1; i++)
            cout << matrix[k*cols+i] << " ";

        for (int i = k; i < rows-k-1; i++)
            cout << matrix[i*cols+cols-k-1] << " ";

        for (int i = cols-k-1; i > k; i--)
            cout << matrix[(rows-k-1)*cols+i] << " ";

        for (int i = rows-k-1; i > k; i--)
            cout << matrix[i*cols+k] << " ";
    }
}

Volendo si può evitare quell'if, ma a fini didattici mi sembra più semplice mostrarlo in questo modo. Tutti e 4 i for hanno lo stesso comportamento: stampare tutti gli elementi di una riga/colonna tranne l'ultimo; l'ultimo elemento di una riga/colonna è considerato come il primo elemento mostrato dal for successivo. L'unico intoppo c'è nel caso l'elemento da stampare è uno solo (elemento centrale in una matrice quadrata di dimensioni dispari), ma questo caso vene gestito dall'if.

Avevi assolutamente ragione... lo ho rifatto usando i for e non ho nemmeno dovuto guardare il codice precedente o il tuo e mi è riuscito al primo tentativo....
Non era perfetto (prova a testarlo a fondo e vedrai tu stesso), ma hai comunque fatto un ottimo lavoro ;)
 
indipendentemente dalle dimensioni della matrice (sia quadrata che rettangolare)
Secondo me ti sei complicato un po' la vita con quel codice... quello postato da Showme, se fosse del tutto corretto, gestirebbe senza alcun problema anche le matrici rettangolari. Eccone una dimostrazione:
C++:
void print_spiral(int *matrix, int rows, int cols) {
int min = rows > cols ? cols : rows;

for (int k = 0; 2*k < min; k++) {
if (k == cols-k-1 && k == rows-k-1)
cout 
for (int i = k; i < cols-k-1; i++)
cout 
for (int i = k; i < rows-k-1; i++)
cout 
for (int i = cols-k-1; i > k; i--)
cout 
for (int i = rows-k-1; i > k; i--)
cout  }
}

Volendo si può evitare quell'if, ma a fini didattici mi sembra più semplice mostrarlo in questo modo. Tutti e 4 i for hanno lo stesso comportamento: stampare tutti gli elementi di una riga/colonna tranne l'ultimo; l'ultimo elemento di una riga/colonna è considerato come il primo elemento mostrato dal for successivo. L'unico intoppo c'è nel caso l'elemento da stampare è uno solo (elemento centrale in una matrice quadrata di dimensioni dispari), ma questo caso vene gestito dall'if.

Avevi assolutamente ragione... lo ho rifatto usando i for e non ho nemmeno dovuto guardare il codice precedente o il tuo e mi è riuscito al primo tentativo....
Non era perfetto (prova a testarlo a fondo e vedrai tu stesso), ma hai comunque fatto un ottimo lavoro ;)
Il mio codice non va mai modificato quando cambi matrice... I vostri listati sono da rivedere per ogni size.. Diciamo che la mia sarebbe la classe che sarebbe rilasciabile in una lib se a qualcuno interesserebbe un metodo che stampi matrici in questo modo.. Il vostro script invece non è generale non sarebbe rilasciabile..

Inviato dal mio LG-H870 utilizzando Tapatalk
 
printa questa matrice rettangolare
int matrix[1][4] = { {0,1,2,3} };
vedrai che il mio codice non ha problemi , il tuo qualche problema lo tiene..
 
anche printando una rettangolare qualunque a dire il vero ora che ho notato meglio fa un difetto
prova tu stesso

Codice:
 int matrix[3][5] =
    {
        {0,1,2,3,4},
        {4,5,6,7,8},
        {8,9,10,11,12}
    };
 
Ultima modifica:
Giustissimo... colpa mia per essere andato frettolosamente senza aver testato più di tanto. Il problema si presenta solo nel momento in cui deve stampare una sola riga/colonna e il primo dirty fix che mi viene in mente in mezzo secondo è splittare in due quella condizione composta nell'if. Ecco qui, ora dovrebbe essere ok:
C++:
#include <iostream>
using namespace std;

void print_spiral(int *matrix, int rows, int cols);

int main() {
    int matrix1[1][4] = { {0,1,2,3} };

    int matrix2[2][4] = { {0,1,2,3},
                          {4,5,6,7} };

    int matrix3[3][4] = { {0,1,2,3},
                          {4,5,6,7},
                          {8,9,10,11} };

    int matrix4[2][2] = { {0,1},
                          {4,5} };

    int matrix5[3][3] = { {1,2,3},
                          {4,5,6},
                          {7,8,9} };

    int matrix6[3][5] = { {0,1,2,3,4},
                         {4,5,6,7,8},
                         {8,9,10,11,12} };

    int matrix7[3][1] = { {0},
                          {1},
                          {2} };

    cout << "matrix1\n"; print_spiral((int*)matrix1, 1, 4); cout << endl;
    cout << "matrix2\n"; print_spiral((int*)matrix2, 2, 4); cout << endl;
    cout << "matrix3\n"; print_spiral((int*)matrix3, 3, 4); cout << endl;
    cout << "matrix4\n"; print_spiral((int*)matrix4, 2, 2); cout << endl;
    cout << "matrix5\n"; print_spiral((int*)matrix5, 3, 3); cout << endl;
    cout << "matrix6\n"; print_spiral((int*)matrix6, 3, 5); cout << endl;
    cout << "matrix7\n"; print_spiral((int*)matrix7, 3, 1); cout << endl;

    return 0;
}


void print_spiral(int *matrix, int rows, int cols) {
    int min = rows > cols ? cols : rows;

    for (int k = 0; 2*k < min; k++) {
        if (k == rows-k-1) {
            for (int i = k; i < cols-k; i++)
                cout << matrix[k*cols+i] << " ";
        } else if (k == cols-k-1) {
            for (int i = k; i < rows-k; i++)
                cout << matrix[i*cols+k] << " ";
        } else {
            for (int i = k; i < cols-k-1; i++)
                cout << matrix[k*cols+i] << " ";
            for (int i = k; i < rows-k-1; i++)
                cout << matrix[i*cols+cols-k-1] << " ";
            for (int i = cols-k-1; i > k; i--)
                cout << matrix[(rows-k-1)*cols+i] << " ";
            for (int i = rows-k-1; i > k; i--)
                cout << matrix[i*cols+k] << " ";
        }
    }
}
 
Stato
Discussione chiusa ad ulteriori risposte.