Ефективна структура для представлення ієрархії перетворень


9

Чи може хтось запропонувати ефективний для пам'яті спосіб представити дерево матриць, наприклад, в ієрархічній моделі?

Я особливо прагну зберегти локалізацію даних, і я підозрюю, що тип підходу до структури масивів (матриць та індексів до матриць) може бути підходящим.

Як і багато обчислених ланцюжком матричних обчислень, ця структура, ймовірно, буде скопійована навколо пам’яті досить небагато, тож наявність суміжного зберігання буде великим бонусом.

Відповіді:


6

Дерево як масив звучить для мене як виграш. Просто пройдіть першу глибину вашої ієрархії та заповніть масив; під час перемотування через рекурсію ви можете або оновити батьківський з абсолютним індексом для дитини, або просто дельта-від-мене, і діти також можуть зберігати батьківські індекси. Дійсно, якщо ви використовуєте відносні компенсації, вам не потрібно носити кореневу адресу навколо. Я гадаю, що структура, мабуть, виглядала б приблизно

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

... тож вам знадобляться вузли, щоб знати, як потрапити до братів і сестер, оскільки ви не можете (легко) мати структуру змінних розмірів. Хоча я здогадуюсь, якщо ви використовували байтове зміщення замість зсуву "Трансформація", ви могли мати змінну кількість дітей за перетворення:

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
};

... тоді вам просто потрібно переконатися, що ви поставите послідовні перетворення в потрібне місце.

Ось як ви будуєте цілком автономне дерево із вбудованими дочірніми «покажчиками».

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);
}

(Якщо ви хочете зберігати відносні місця, просто додайте - currentLocationдо двох записів "location".)


Якщо ми говоримо на C ++, вам потрібно буде вказати розмір дочірнього масиву або створити його під час виконання з розподілом пам'яті.
tenpn

Офіційний спосіб, затверджений C99, - залишити порожню специфікацію масиву.

@ tenpn - ідея полягає у тому, що у вас є цільовий буфер, побудований за призначенням. Вся справа в тому, щоб уникнути зайвих виділень; ви не можете вказати розмір масиву, оскільки ви не знаєте, наскільки він буде великим. Після того, як ви записуєте кількість дітей, ви записуєте у свій дочірній масив, але потім наступна Трансформація починається після закінчення дочірнього масиву. (Ось чому для цієї структури потрібно використовувати зміщення байтів, а не індекси; ви не знаєте, наскільки велика кожна запис, але вона все ще ефективна для переходу та є самодостатньою, щоб вона могла рухатись як одиниця.)
dash -tom-bang

1
Це називається "хакерство". Дивіться також: informit.com/guides/content.aspx?g=cplusplus&seqNum=288
Neverender

1
@tenpn Aka структури змінної довжини. Використовуючи належним чином, вони можуть вдвічі зменшити кількість виділень.

1

Індексація в масив матриць, мабуть, буде найбільш прямим, ефективним підходом до пам'яті.

Ланцюг перетворень може бути проведено в LIFO у вигляді рядів покажчиків або цілих чисел чи іншої невеликої структури, що індексується в матричний масив. Це допоможе запобігти збереженню зайвих матриць і відокремить код зберігання даних від коду доступу даних.

Зрештою, ви просто натискаєте та попсові значення індексу з LIFO, щоб зберігати або відтворювати свою ланцюжок трансформацій.

Можливо, ви також зможете зекономити трохи пам'яті, якщо ваша матрична структура також може містити тип перетворення ... обертання, переклад тощо. Інакше тип потрібно буде зберігати з індексом, що призводить до більш можливого дублювання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.