Struttura efficiente per rappresentare una gerarchia di trasformazione


9

Qualcuno può suggerire un modo efficiente della memoria per rappresentare un albero di matrici, ad esempio in un modello gerarchico?

Sono particolarmente interessato a preservare la localizzazione dei dati e sospetto che un approccio di tipo struttura di matrici (matrici e indici a matrici) possa essere adatto.

Oltre a molti calcoli a matrice concatenata, questa struttura sarà probabilmente copiata in memoria un po 'in memoria, quindi avere una memoria contigua sarebbe un grosso vantaggio.

Risposte:


6

La struttura ad albero mi sembra una vittoria. Fai solo un attraversamento approfondito della tua gerarchia e compila un array; quando riavvolgi attraverso la ricorsione puoi aggiornare il genitore con l'indice assoluto al figlio o solo il delta-da-me, e anche i figli possono memorizzare gli indici del genitore in entrambi i modi. Infatti, se si utilizzano offset relativi, non è necessario portare in giro l'indirizzo di root. Suppongo che la struttura probabilmente assomiglierebbe a qualcosa di simile

struct Transform
{
   Matrix m; // whatever you like
   int parent;   // index or offset, you choose!
   int sibling;
   int firstchild;
};

... quindi avresti bisogno di nodi per sapere come arrivare anche ai fratelli poiché non puoi (facilmente) avere una struttura di dimensioni variabili. Anche se suppongo che se hai utilizzato offset di byte anziché offset di trasformazione, potresti avere un numero variabile di figli per trasformazione:

struct Transform
{
   Matrix m; // whatever you like
   int parent;  // negative byte offest
   int numchildren;
   int child[0]; // can't remember if you put a 0 there or leave it empty;
                 // but it's an array of positive byte offsets
};

... allora devi solo assicurarti di mettere le trasformazioni successive nel posto giusto.

Ecco come creare un albero totalmente autonomo con "puntatori" figlio incorporati.

int BuildTransforms(Entity* e, OutputStream& os, int parentLocation)
{
    int currentLocation = os.Tell();

    os.Write(e->localMatrix);
    os.Write(parentLocation);
    int numChildren = e->GetNumChildren();
    os.Write(numChildren);

    int childArray = os.Tell();
    os.Skip(numChildren * sizeof(int));
    os.AlignAsNecessary();  // if you need to align transforms

    childLocation = os.Tell();
    for (int i = 0; i < numChildren; ++i) {
        os.Seek(childArray + (i * sizeof(int)));
        os.Write(childLocation);
        os.Seek(childLocation);
        childLocation = BuildTransforms(e->GetChild(i), os, currentLocation);
    }

    return os.Tell();
}

void BuildTransforms(Entity* root)
{
    OutputStream os;
    BuildTransforms(root, os, -1, 0);
}

(Se si desidera memorizzare posizioni relative, è sufficiente aggiungere - currentLocationalle due scritture "posizione".)


Se stiamo parlando di C ++, dovrai specificare una dimensione per il tuo array figlio o crearla in fase di esecuzione con un'allocazione di memoria.
dieci

Il modo ufficiale approvato da C99 è di lasciare vuote le specifiche di dimensione dell'array.

@ tenpn- l'idea è che hai un buffer appositamente costruito. Il punto è evitare allocazioni extra; non puoi specificare la dimensione dell'array perché non sai quanto sarà grande. Dopo aver scritto num figli, si scrive nell'array figlio, ma la trasformazione successiva inizia dopo la fine dell'array figlio. (Questo è il motivo per cui devi usare offset di byte e non indici per questa struttura; non sai quanto sia grande ogni voce, ma è comunque efficiente da attraversare ed è autonomo in modo che possa muoversi come un'unità.)
trattino -tom-bang

1
Questo si chiama "struct hack". Vedi anche: informit.com/guides/content.aspx?g=cplusplus&seqNum=288
Neverender

1
@tenpn Aka strutture a lunghezza variabile. Se utilizzati in modo appropriato, possono dimezzare il numero di allocazioni di heap.

1

L'indicizzazione in una matrice di matrici sarebbe probabilmente l'approccio più diretto ed efficiente in termini di memoria.

Una catena di trasformazioni potrebbe essere mantenuta in un LIFO come una serie di puntatori o numeri interi o altre piccole strutture che si indicizzano nella matrice matrice. Ciò contribuirebbe a prevenire la memorizzazione di matrici ridondanti e separerebbe il codice di archiviazione dei dati dal codice di accesso ai dati.

Alla fine dovresti semplicemente spingere e far apparire i valori dell'indice dal LIFO per memorizzare o riprodurre la catena di trasformazione.

Potresti anche essere in grado di risparmiare un po 'di memoria se la tua struttura a matrice potrebbe contenere anche il tipo di trasformazione ... rotazione, traduzione, ecc. Altrimenti il ​​tipo dovrebbe essere archiviato con l'indice con conseguente possibile duplicazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.