หนึ่งในกรณีที่มีประโยชน์ที่สุดที่ฉันพบสำหรับรายการที่เชื่อมโยงซึ่งทำงานในช่องที่มีความสำคัญต่อประสิทธิภาพเช่นการประมวลผลแบบเมชและการประมวลผลภาพเอ็นจินฟิสิกส์และการเรย์เทรนคือเมื่อใช้รายการที่เชื่อมโยงจะช่วยปรับปรุงตำแหน่งของการอ้างอิงและลดการจัดสรรฮีปและบางครั้งยังลดการใช้หน่วยความจำเมื่อเทียบกับ ทางเลือกที่ตรงไปตรงมา
ตอนนี้ดูเหมือนว่าเป็น oxymoron ที่สมบูรณ์ซึ่งรายการที่เชื่อมโยงสามารถทำทุกอย่างได้เนื่องจากพวกเขามีชื่อเสียงในเรื่องที่มักจะทำตรงกันข้าม แต่มีคุณสมบัติที่ไม่ซ้ำกันในแต่ละโหนดรายการมีขนาดคงที่และข้อกำหนดในการจัดตำแหน่งซึ่งเราสามารถใช้ประโยชน์ได้เพื่ออนุญาต จะถูกจัดเก็บอย่างต่อเนื่องและลบออกในเวลาคงที่ในรูปแบบที่สิ่งที่มีขนาดผันแปรไม่สามารถทำได้
ด้วยเหตุนี้ลองมาในกรณีที่เราต้องการทำเทียบเท่าแบบอะนาล็อกของการจัดเก็บลำดับความยาวผันแปรซึ่งมีลำดับย่อยที่มีความยาวตัวแปรซ้อนกันล้านลำดับ ตัวอย่างที่เป็นรูปธรรมคือตาข่ายที่จัดทำดัชนีซึ่งเก็บรูปหลายเหลี่ยมหลายล้านรูป (สามเหลี่ยมบางรูปสี่เหลี่ยมบางรูปห้าเหลี่ยมบางรูปหกเหลี่ยม ฯลฯ ) และบางครั้งรูปหลายเหลี่ยมจะถูกลบออกจากที่ใดก็ได้ในตาข่ายและบางครั้งรูปหลายเหลี่ยมจะถูกสร้างขึ้นใหม่เพื่อแทรกจุดยอดไปยังรูปหลายเหลี่ยมที่มีอยู่หรือ ลบออก ในกรณีนี้ถ้าเราเก็บไว้ได้หนึ่งล้านชิ้นstd::vectors
เราก็จะต้องเจอกับการจัดสรรฮีปสำหรับเวกเตอร์ทุกตัวรวมถึงการใช้หน่วยความจำที่อาจระเบิดได้ ล้านตัวเล็ก ๆSmallVectors
อาจไม่ประสบปัญหานี้เท่าในกรณีทั่วไป แต่บัฟเฟอร์ที่จัดสรรไว้ล่วงหน้าซึ่งไม่ได้จัดสรรฮีปแยกต่างหากอาจทำให้การใช้หน่วยความจำระเบิดได้
ปัญหาตรงนี้เป็นล้าน std::vector
อินสแตนซ์พยายามจัดเก็บสิ่งที่มีความยาวผันแปรได้เป็นล้านรายการ สิ่งที่มีความยาวตัวแปรมักจะต้องการการจัดสรรฮีปเนื่องจากไม่สามารถจัดเก็บได้อย่างมีประสิทธิภาพอย่างต่อเนื่องและลบออกในเวลาคงที่ (อย่างน้อยก็ตรงไปตรงมาโดยไม่มีตัวจัดสรรที่ซับซ้อนมาก) หากพวกเขาไม่ได้เก็บเนื้อหาไว้ที่อื่นในฮีป
หากเราทำสิ่งนี้แทน:
struct FaceVertex
{
// Points to next vertex in polygon or -1
// if we're at the end of the polygon.
int next;
...
};
struct Polygon
{
// Points to first vertex in polygon.
int first_vertex;
...
};
struct Mesh
{
// Stores all the face vertices for all polygons.
std::vector<FaceVertex> fvs;
// Stores all the polygons.
std::vector<Polygon> polys;
};
... จากนั้นเราได้ลดจำนวนการจัดสรรฮีปลงอย่างมากและการพลาดแคช แทนที่จะต้องมีการจัดสรรฮีปและอาจพลาดแคชบังคับสำหรับทุก ๆ รูปหลายเหลี่ยมที่เราเข้าถึงตอนนี้เราต้องการการจัดสรรฮีปนั้นก็ต่อเมื่อเวกเตอร์หนึ่งในสองตัวที่เก็บไว้ในตาข่ายทั้งหมดเกินความจุ (ต้นทุนที่ตัดจำหน่าย) และในขณะที่การก้าวข้ามจากจุดยอดหนึ่งไปยังจุดถัดไปอาจทำให้ส่วนแบ่งของแคชขาดหายไป แต่ก็มักจะน้อยกว่าถ้าทุก ๆ รูปหลายเหลี่ยมเก็บอาร์เรย์แบบไดนามิกแยกกันเนื่องจากโหนดจะถูกเก็บไว้ติดกันและมีความเป็นไปได้ที่จุดยอดใกล้เคียงอาจ สามารถเข้าถึงได้ก่อนการขับไล่ (โดยเฉพาะอย่างยิ่งเมื่อพิจารณาว่ารูปหลายเหลี่ยมจำนวนมากจะเพิ่มจุดยอดทั้งหมดพร้อมกันซึ่งทำให้ส่วนแบ่งของจุดยอดรูปหลายเหลี่ยมของสิงโตติดกันอย่างสมบูรณ์แบบ)
นี่คืออีกตัวอย่างหนึ่ง:
... ที่ซึ่งเซลล์กริดถูกใช้เพื่อเร่งการชนกันของอนุภาคและอนุภาคกล่าวคืออนุภาค 16 ล้านอนุภาคเคลื่อนที่ทุกเฟรม ในตัวอย่างตารางอนุภาคนั้นการใช้รายการที่เชื่อมโยงเราสามารถย้ายอนุภาคจากเซลล์กริดหนึ่งไปยังอีกเซลล์หนึ่งได้โดยเปลี่ยนดัชนีเพียง 3 ตัว การลบจากเวกเตอร์และการผลักกลับไปที่อื่นอาจมีราคาแพงกว่ามากและแนะนำการจัดสรรฮีปให้มากขึ้น รายการที่เชื่อมโยงยังลดหน่วยความจำของเซลล์ลงเหลือ 32 บิต เวกเตอร์ขึ้นอยู่กับการนำไปใช้งานสามารถจัดสรรอาร์เรย์แบบไดนามิกไปยังจุดที่สามารถใช้ 32 ไบต์สำหรับเวกเตอร์ว่างได้ ถ้าเรามีกริดเซลล์ประมาณล้านเซลล์นั่นเป็นความแตกต่างอย่างมาก
... และนี่คือที่ที่ฉันพบว่ารายการที่เชื่อมโยงมีประโยชน์มากที่สุดในปัจจุบันและฉันพบว่า "รายการลิงก์ที่จัดทำดัชนี" มีประโยชน์โดยเฉพาะเนื่องจากดัชนี 32 บิตช่วยลดความต้องการหน่วยความจำของลิงก์บนเครื่อง 64 บิตลงครึ่งหนึ่งและหมายความว่า โหนดจะถูกจัดเก็บอย่างต่อเนื่องในอาร์เรย์
บ่อยครั้งที่ฉันรวมเข้ากับรายการฟรีที่จัดทำดัชนีเพื่อให้สามารถลบและแทรกเวลาคงที่ได้ทุกที่:
ในกรณีนั้นnext
ดัชนีจะชี้ไปยังดัชนีว่างถัดไปหากโหนดถูกลบออกหรือดัชนีที่ใช้ถัดไปหากโหนดยังไม่ถูกลบออก
และนี่คือกรณีการใช้งานอันดับหนึ่งที่ฉันพบสำหรับรายการที่เชื่อมโยงในทุกวันนี้ เมื่อเราต้องการจัดเก็บลำดับย่อยที่มีความยาวผันแปรได้นับล้านรายการโดยเฉลี่ยแต่ละองค์ประกอบ 4 รายการ (แต่บางครั้งก็มีการลบองค์ประกอบและเพิ่มในลำดับย่อยเหล่านี้) รายการที่เชื่อมโยงทำให้เราสามารถจัดเก็บได้ 4 ล้าน โหนดรายการที่เชื่อมโยงติดๆกันแทนที่จะเป็น 1 ล้านคอนเทนเนอร์ซึ่งแต่ละรายการจะจัดสรรเป็นฮีปแยกกัน: เวกเตอร์ขนาดยักษ์ 1 ตัวนั่นคือไม่ใช่หนึ่งล้านเล็ก ๆ