โครงสร้างที่มีประสิทธิภาพสำหรับการแทนลำดับชั้นการแปลง


9

ใครสามารถแนะนำวิธีที่มีประสิทธิภาพของหน่วยความจำเพื่อเป็นตัวแทนของต้นไม้ของเมทริกซ์ตัวอย่างเช่นในโมเดลลำดับชั้น?

ฉันมีความกระตือรือร้นเป็นพิเศษในการรักษาตำแหน่งของข้อมูลและฉันสงสัยว่าแนวทางแบบโครงสร้างของอาร์เรย์ (เมทริกซ์และดัชนีกับเมทริกซ์) อาจเหมาะสม

เช่นเดียวกับการคำนวณเมทริกซ์ที่ถูกล่ามโซ่โครงสร้างนี้อาจจะถูกคัดลอกไปรอบ ๆ ในหน่วยความจำอย่างยุติธรรมดังนั้นการมีพื้นที่เก็บข้อมูลติดกันจะเป็นโบนัสก้อนโต

คำตอบ:


6

ต้นไม้แบบอาเรย์ดูเหมือนจะชนะฉัน เพียงทำการสำรวจเชิงลึกของลำดับชั้นของคุณและกรอกข้อมูลในอาร์เรย์ เมื่อกรอกลับผ่านการสอบถามซ้ำคุณสามารถอัปเดตพาเรนต์ด้วยดัชนีสัมบูรณ์เป็น child หรือเพียง delta-from-me และเด็ก ๆ ก็สามารถจัดเก็บดัชนีพาเรนต์ได้เช่นกัน แน่นอนถ้าคุณใช้ offsets สัมพัทธ์แล้วคุณไม่จำเป็นต้องดำเนินการที่อยู่รากรอบ ๆ ฉันคิดว่าโครงสร้างอาจมีลักษณะเหมือน

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- แนวคิดคือคุณมีบัฟเฟอร์ที่สร้างขึ้นตามวัตถุประสงค์ จุดทั้งหมดคือการหลีกเลี่ยงการจัดสรรพิเศษ; คุณไม่สามารถระบุขนาดอาร์เรย์ได้เนื่องจากคุณไม่รู้ว่ามันจะใหญ่แค่ไหน หลังจากที่คุณเขียนลูกย่อยคุณเขียนลงในอาร์เรย์ลูกของคุณ แต่จากนั้นการแปลงถัดไปจะเริ่มขึ้นหลังจากที่อาร์เรย์ลูกจบ (นี่คือเหตุผลที่คุณจำเป็นต้องใช้ชดเชยไบต์และไม่ดัชนีสำหรับโครงสร้างนี้คุณไม่ทราบวิธีการใหญ่แต่ละรายการเป็น แต่มันมีประสิทธิภาพเพื่อสำรวจและยังคงเป็นตัวเองที่มีอยู่เพื่อที่จะสามารถย้ายเป็นหน่วย.)
ประ -tom-bang

1
สิ่งนี้เรียกว่า "แฮ็ค struct" ดูเพิ่มเติมได้ที่: informit.com/guides/content.aspx?g=cplusplus&seqNum=288
Neverender

1
@tenpn Aka ความยาวผันแปรของตัวแปร ใช้อย่างเหมาะสมพวกเขาสามารถลดจำนวนการจัดสรรฮีปได้ครึ่งหนึ่ง

1

การจัดทำดัชนีในอาเรย์ของเมทริกซ์น่าจะเป็นวิธีที่มีประสิทธิภาพมากที่สุด

สายโซ่การแปลงรูปสามารถจัดขึ้นใน LIFO เป็นชุดพอยน์เตอร์หรือจำนวนเต็มหรือโครงสร้างขนาดเล็กอื่น ๆ ที่ดัชนีลงในอาร์เรย์เมทริกซ์ สิ่งนี้จะช่วยป้องกันการจัดเก็บเมทริกซ์ที่ซ้ำซ้อนและจะแยกรหัสการจัดเก็บข้อมูลออกจากรหัสการเข้าถึงข้อมูล

ในที่สุดคุณก็แค่กดและป๊อปอัพค่าดัชนีจาก LIFO เพื่อจัดเก็บหรือเล่นเชนการแปลงของคุณ

คุณอาจบันทึกหน่วยความจำเล็กน้อยได้หากโครงสร้างเมทริกซ์ของคุณอาจมีการแปลงชนิด ... การหมุนการแปล ฯลฯ มิฉะนั้นประเภทจะต้องถูกเก็บไว้กับดัชนีทำให้มีความซ้ำซ้อนได้มากขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.