Domanda di complessità ciclomatica

3

Ho una domanda generale relativa alla complessità ciclomatica. Si prega di dare un'occhiata al codice sorgente allegato:

private void downShift(int index)
{
    // index of "child", which will be either index * 2 or index * 2 + 1
    int childIndex;

    // temp storage for item at index where shifting begins
    Comparable temp = theItems[index];

    // shift items, as needed
    while (index * 2 <= theSize)
    {
        // set childIndex to "left" child
        childIndex = index * 2;

        // move to "right" child if "right" child < "left" child
        if (childIndex != theSize && theItems[childIndex + 1].compareTo(theItems[childIndex]) < 0)
            childIndex++;

        if (theItems[childIndex].compareTo(temp) < 0)
        {
        // shift "child" down if child < temp
            theItems[index] = theItems[childIndex];
        }
        else
        {
            // shifting complete
            break;
        }

        // increment index
        index = childIndex;
    }

    // position item that was originally at index where shifting began
    theItems[index] = temp;
}

Dal codice precedente, ho disegnato un grafico di flusso come illustrato qui:

e ho contato il numero di nodi da 10 e anche il numero di bordi da 10. Usando la seguente formula, V (G) = E - N + 2P, ho calcolato 3 come complessità ciclomatica (o V (G)).

Il mio calcolo è corretto? Grazie!

    
posta Al-geBra 23.02.2018 - 01:08
fonte

1 risposta

4

Non sono convinto che il grafico del flusso di controllo sia corretto perché mostra due nodi terminali 9 e 12. Invece, dovrebbe esserci un singolo nodo terminale per il ritorno.

Una difficoltà con il tuo codice è che contiene molti dettagli irrilevanti ai fini del calcolo della complessità ciclomatica. Quindi passiamo al relativo flusso di controllo:

f() {
    ...;                  // enter
    while (condWhile) {   // whilecond
        ...;              // whilebody
        if (condIncr)
            ...;          // incr
        if (condNoBreak)  // ifbreak
            ...;          // whileend
        else
            break;
        ...;              // whileend
    }
    ...;                  // end
}

Vale la pena notare che il flusso di controllo if (cond) { a(); } else { break; } b(); è equivalente a if (!cond) { break; } a(); b(); . Tenendo presente ciò, possiamo separare il codice in blocchi di base . Un blocco di base inizia con un obiettivo di salto e termina con un salto o un ramo su un altro blocco di base.

Se dividi il codice sorgente in più blocchi di base non è un problema. Ciò porterà comunque alla stessa complessità, poiché un blocco non necessario aggiunge un bordo e un vertice al grafico del flusso di controllo, che si annulla a vicenda. Ecco i blocchi di base in stile assembly che ho scelto:

ENTER:
  ...
  jump WHILECOND
WHILECOND:
  branch condWhile ? WHILE : END
WHILEBODY:
  ...
  branch condIncr ? INCR : IFBREAK
INCR:
  ...
  jump IFBREAK
IFBREAK:
  branch condNoBreak ? WHILEEND : END
WHILEEND:
  ...
  ...
  jump WHILECOND
END:
  ...
  return

Ora possiamo disegnare il grafico del flusso di controllo:

control flow graph

Questo è un grafico abbastanza complesso, ma ho cercato di disporlo come un grafico planare che corrisponde all'incirca all'aspetto del codice sorgente.

Esistono numerose differenze sostanziali nel tuo grafico. Per esempio. hai solo un singolo percorso che lascia il ciclo. Questo ignora che sia la condizione del ciclo che break possono lasciare il ciclo. E una volta inserito il corpo del ciclo, il tuo grafico non continua.

Possiamo vedere che il CC di questa funzione è 4, applicando la formula o contando manualmente i percorsi indipendenti.

Questo dimostra anche che CC come metrica della qualità del software ha i suoi limiti. Il codice che hai mostrato è molto complesso e non facile da capire. Tuttavia ha lo stesso CC di questo metodo molto più semplice (notare che && è un operatore di controllo del flusso):

boolean inBounds(int x, int y) {
  return (0 <= x) && (x < 10)
      && (0 <= y) && (y < 10);
}
    
risposta data 23.02.2018 - 13:46
fonte

Leggi altre domande sui tag