พื้นที่ที่มีประสิทธิภาพที่สุดในการใช้โครงสร้างข้อมูลกราฟคืออะไร?


14

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

คำตอบ:


12

ถ้าประสิทธิภาพของพื้นที่เป็นสิ่งที่คุณใส่ใจโครงสร้างข้อมูลที่บีบอัดจะดีที่สุด - แต่แน่นอนว่านี่ไม่ใช่ประสิทธิภาพในการเข้าถึงหรืออัพเดท .....

หากกราฟของคุณมีจำนวนโหนดค่อนข้างน้อยและค่อนข้างหนาแน่น (ให้พูดอย่างน้อย 5% ของการเชื่อมต่อที่เป็นไปได้ทั้งหมด) จากนั้นคุณอาจพบว่าพื้นที่มีประสิทธิภาพมากกว่าในการสร้างเมทริกซ์ adjacencyแทนที่จะใช้รายการขอบ สิ่งนี้ต้องการการเชื่อมต่อ (กำกับ) ที่เป็นไปได้เพียงหนึ่งบิตและรวม n * n บิตที่คุณมีโหนด n

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

มีเทคนิคบางอย่างที่คุณสามารถลองได้ ตัวอย่างเช่นคุณสามารถลองแชร์ลิงก์ย่อย (ถ้า A และ B อ้างถึงแต่ละ C, D, E จากนั้นเก็บเฉพาะรายการลิงก์ C, D, E หนึ่งครั้ง ..... ) อย่างไรก็ตามสิ่งนี้จะซับซ้อนขึ้นอย่างรวดเร็วและฉันสงสัยว่ามันจะคุ้มค่ากับความพยายามในกรณีส่วนใหญ่

อีกหนึ่งเคล็ดลับ - สมมติว่ากราฟของคุณมีจำนวนโหนดพอสมควรคุณจะประหยัดพื้นที่ได้อย่างแน่นอนโดยการทำดัชนี - เช่นการใช้หมายเลขดัชนีโหนดแบบ 16 บิตแทนที่จะเป็นตัวชี้ / การอ้างอิงแบบเต็ม


หากลิงก์ทั้งหมดไม่ได้กำกับทิศทางหนึ่งสามารถประหยัดพื้นที่ครึ่งหนึ่งได้ด้วยการบันทึกขอบจากโหนดต่ำถึงโหนดสูงเท่านั้น
Deduplicator

6

มันจะขึ้นอยู่กับโครงสร้างข้อมูลของคุณ

สำหรับกราฟที่มีความหนาแน่นสูงที่มีขอบที่ไม่ได้บอกทิศทางคุณจะไม่สามารถเอาชนะรายการอาร์เรย์บิตที่เป็นตัวแทนของเมทริกซ์รูปสามเหลี่ยมได้ List<BitArray>ตัวอย่างเช่น ตามหลักตรรกะแล้วมันจะมีลักษณะเช่นนี้:

 0123
0
11
211
3001
41010

จากตรงนั้นคุณสามารถใช้ดัชนีของรูต BitArray เพื่อทำดัชนีลงในรายการที่เก็บข้อมูลโหนดของคุณ

ตัวอย่างเช่นการรับเพื่อนบ้านทั้งหมดของโหนดจะเป็นไปดังนี้:

// C#
List<Node> Nodes = /* populated elsewhere */
List<BitArray> bits = /* populated elsewhere */
public static IEnumerable<Node> GetNeighbours(int x)    
{
    for (int i = 0; i < bits[idx].Count; i++)
    {
        if (this.bits[idx][i])
            yield return this.Nodes[i];
    }

    for (int i = 0; i < this.Nodes.Count; i++)
    {
        if (idx < this.bits[i].Count && this.bits[i][idx])
            yield return this.Nodes[i];
    }    
}

(โปรดทราบว่าคุณยังสามารถเลือกประเภทดัชนีขึ้นอยู่กับปริมาณของข้อมูลเป็นไบต์หรือ ushort หรือบางสิ่งบางอย่างตามบรรทัดเหล่านั้นเนื่องจากดัชนีทั้งหมดจะเป็นค่าบวกฉันไม่คิดว่านี่เป็นการเพิ่มประสิทธิภาพแบบไมโครเพราะมันไม่สำคัญ)

สำหรับกราฟที่กำกับแล้วคุณจะไปยังเส้นทางของบิต * n เพื่อเก็บการเชื่อมต่อ ... เว้นเสียแต่ว่ามันจะเบาบางมากเมื่อเทียบกับจำนวนโหนดที่คุณสามารถไปที่รายการดัชนี

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