변환 계층을 표현하기위한 효율적인 구조


9

누구나 계층 구조 모델과 같이 행렬 트리를 표현하는 메모리 효율적인 방법을 제안 할 수 있습니까?

특히 데이터 지역성을 유지하려고 애 쓰고 있으며 배열 구조 (행렬 및 행렬에 대한 행렬) 유형의 접근 방식이 적합 할 것으로 생각됩니다.

많은 연쇄 행렬 계산뿐만 아니라이 구조는 메모리에 상당히 복사 될 것이므로 연속 저장이 큰 보너스입니다.

답변:


6

배열로서의 나무는 나에게 승리처럼 들린다. 계층의 깊이 우선 탐색을 수행하고 배열을 채우십시오. 재귀를 되감기 할 때 절대 인덱스를 사용하여 부모를 자식이나 delta-from-me로 업데이트하고 자식은 부모 인덱스를 어느 쪽이든 저장할 수 있습니다. 실제로 상대 오프셋을 사용하는 경우 루트 주소를 옮길 필요가 없습니다. 나는 아마도 구조가 다음과 같이 보일 것이라고 생각합니다

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하려면 두 개의 "위치"쓰기에 추가하십시오 .)


C ++을 사용하는 경우 자식 배열의 크기를 지정하거나 런타임시 메모리 할당을 사용하여 자식 배열의 크기를 지정해야합니다.
tenpn

공식 C99 승인 방법은 어레이 크기 사양을 비워 두는 것입니다.

@ tenpn- 아이디어는 당신이 목적으로 만든 버퍼를 가지고 있다는 것입니다. 요점은 추가 할당 을 피하는 것입니다 . 얼마나 큰지 모르기 때문에 배열 크기를 지정할 수 없습니다. num 개의 자식을 쓴 후 자식 배열에 쓰지만 자식 배열이 끝나면 다음 Transform이 시작됩니다. (따라서이 구조에 대해 인덱스가 아닌 바이트 오프셋을 사용해야하는 이유입니다. 각 항목의 크기를 모르지만, 트래버스하는 것이 여전히 효율적이며 자체 포함되므로 단위로 이동할 수 있습니다.)
dash -tom-bang

1
이것을 "struct hack"이라고합니다. 또한보십시오 : informit.com/guides/content.aspx?g=cplusplus&seqNum=288
Neverender

1
@tenpn 일명 가변 길이 구조체. 적절하게 사용하면 힙 할당 수를 절반으로 줄일 수 있습니다.

1

행렬 배열로 인덱싱하는 것은 아마도 가장 간단하고 메모리 효율적인 방법 일 것입니다.

일련의 포인터 또는 정수 또는 행렬 배열로 색인되는 다른 작은 구조체로 LIFO에 변환 체인을 보유 할 수 있습니다. 이를 통해 중복 매트릭스 저장을 방지하고 데이터 액세스 코드와 데이터 스토리지 코드를 분리 할 수 ​​있습니다.

궁극적으로 LIFO에서 인덱스 값을 푸시 앤 팝하여 변환 체인을 저장하거나 재생할 수 있습니다.

행렬 구조에 변환 유형 ... 회전, 변환 등이 포함될 수있는 경우 약간의 메모리를 절약 할 수도 있습니다. 그렇지 않으면 유형이 색인과 함께 저장되어 중복 가능성이 높아집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.