ฉันไม่ค่อยใช้ตัวชี้หางสำหรับรายการที่เชื่อมโยงและมักจะใช้รายการที่เชื่อมโยงเดี่ยว ๆ บ่อยครั้งที่รูปแบบการแทรกและการเอาออกแบบกองซ้อน - เหมือนแบบกด / ป๊อป เป็นเพราะในกรณีการใช้งานทั่วไปของฉันตัวชี้ส่วนท้ายนั้นมีราคาแพงเช่นเดียวกับการสร้างรายการที่เชื่อมโยงโดยลำพังเป็นรายการที่เชื่อมโยงเป็นสองเท่ามีราคาแพง
บ่อยครั้งที่การใช้กรณีทั่วไปของฉันสำหรับรายการที่เชื่อมโยงโดยลำพังอาจจัดเก็บรายการที่เชื่อมโยงหลายแสนรายการซึ่งมีเพียงไม่กี่โหนดรายการเท่านั้น ฉันมักจะไม่ใช้ตัวชี้สำหรับรายการที่เชื่อมโยง ฉันใช้ดัชนีเป็นอาร์เรย์แทนเนื่องจากดัชนีสามารถเป็นแบบ 32 บิตเช่นใช้พื้นที่ครึ่งหนึ่งของตัวชี้แบบ 64 บิต ฉันมักจะไม่จัดสรรลิสต์ของโหนดทีละรายการและอีกครั้งเพียงใช้อาร์เรย์ขนาดใหญ่เพื่อเก็บโหนดทั้งหมดแล้วใช้ดัชนี 32- บิตเพื่อเชื่อมโยงโหนดเข้าด้วยกัน
ตัวอย่างลองจินตนาการถึงวิดีโอเกมที่ใช้กริด 400x400 เพื่อแบ่งพาร์ติชั่นนับล้านอนุภาคที่เคลื่อนที่ไปรอบ ๆ และกระเด็นออกจากกันเพื่อเร่งการตรวจจับการชน ในกรณีนี้วิธีที่มีประสิทธิภาพในการจัดเก็บนั่นคือการจัดเก็บรายการที่เชื่อมโยงเดี่ยว 160,000 รายการซึ่งแปลเป็นจำนวนเต็ม 160,000 32 บิตในกรณีของฉัน (~ 640 กิโลไบต์) และค่าใช้จ่ายจำนวนเต็ม 32 บิตต่อหนึ่งอนุภาค ตอนนี้เมื่ออนุภาคเคลื่อนที่ไปมาบนหน้าจอสิ่งที่เราต้องทำคืออัพเดตจำนวนเต็ม 32- บิตไม่กี่ตัวเพื่อย้ายอนุภาคจากเซลล์หนึ่งไปยังอีกเซลล์หนึ่งเช่น:
... โดยใช้next
ดัชนี ("ตัวชี้") ของโหนดอนุภาคที่ทำหน้าที่เป็นดัชนีไปยังอนุภาคถัดไปในเซลล์หรืออนุภาคอิสระถัดไปเพื่อเรียกคืนหากอนุภาคเสียชีวิต (โดยทั่วไปคือการใช้ตัวจัดสรรรายการอิสระโดยใช้ดัชนี):
การลบเชิงเส้นเวลาออกจากเซลล์ไม่ใช่ค่าใช้จ่ายจริงเนื่องจากเรากำลังประมวลผลลอจิกของอนุภาคโดยวนซ้ำผ่านอนุภาคในเซลล์ดังนั้นรายการที่เชื่อมโยงเป็นสองเท่าจะเพิ่มค่าใช้จ่ายที่ไม่เป็นประโยชน์ ทั้งหมดในกรณีของฉันเช่นเดียวกับหางจะไม่เป็นประโยชน์กับฉันเลย
ตัวชี้ท้ายจะเพิ่มการใช้หน่วยความจำของกริดเป็นสองเท่ารวมถึงการเพิ่มจำนวนของแคชที่หายไป นอกจากนี้ยังต้องการการแทรกเพื่อกำหนดให้สาขาตรวจสอบว่ารายการว่างเปล่าแทนที่จะเป็นสาขาหรือไม่ การทำให้เป็นลิสต์ที่เชื่อมโยงเป็นสองเท่าจะทำให้ค่าใช้จ่ายในรายการของแต่ละอนุภาคเพิ่มขึ้นเป็นสองเท่า 90% ของเวลาที่ฉันใช้ลิสต์เชื่อมโยงมันเป็นกรณีเหล่านี้และดังนั้นพอยน์เตอร์หางจึงค่อนข้างแพงในการจัดเก็บ
ดังนั้นจริง ๆ แล้ว 4-8 ไบต์ไม่น่ารำคาญในบริบทส่วนใหญ่ที่ฉันใช้รายการเชื่อมโยงในตอนแรก แค่อยากจะใส่เข้าไปในนั้นเพราะถ้าคุณกำลังใช้โครงสร้างข้อมูลเพื่อจัดเก็บองค์ประกอบของเรือจำนวน 4-8 ไบต์อาจไม่สำคัญเลย ฉันใช้ลิสต์ที่เชื่อมโยงเพื่อลดการจัดสรรหน่วยความจำจำนวนและจำนวนหน่วยความจำที่ต้องการซึ่งตรงกันข้ามกับการพูดการจัดเก็บอาร์เรย์แบบไดนามิก 160,000 รายการที่เติบโตสำหรับกริดซึ่งจะมีการใช้หน่วยความจำแบบระเบิด พร้อมกับการจัดสรรฮีปต่อเซลล์กริดซึ่งตรงข้ามกับการจัดสรรฮีปเดียวจำนวนเต็มหนึ่งศูนย์และศูนย์ต่อเซลล์)
ฉันมักจะพบว่ามีคนจำนวนมากที่เข้าถึงรายการที่เชื่อมโยงสำหรับความซับซ้อนของเวลาคงที่ที่เกี่ยวข้องกับการลบด้านหน้า / กลางและการแทรกด้านหน้า / กลางเมื่อ LLs มักจะเป็นตัวเลือกที่ไม่ดีในกรณีเหล่านี้เนื่องจากขาดความต่อเนื่องทั่วไป LL ที่สวยงามสำหรับฉันจากจุดยืนด้านประสิทธิภาพคือความสามารถในการย้ายองค์ประกอบหนึ่งจากรายการหนึ่งไปอีกรายการหนึ่งโดยจัดการกับตัวชี้ไม่กี่ตัวและสามารถบรรลุโครงสร้างข้อมูลขนาดตัวแปรโดยไม่มีตัวจัดสรรหน่วยความจำขนาดตัวแปร (ตั้งแต่ แต่ละโหนดมีขนาดที่เหมือนกันเราสามารถใช้รายการฟรีเช่น) หากแต่ละโหนดรายการถูกจัดสรรเป็นรายบุคคลเทียบกับตัวจัดสรรวัตถุประสงค์ทั่วไปนั่นคือเมื่อรายการที่เชื่อมโยงรายการค่าโดยสารแย่ลงมากเมื่อเทียบกับทางเลือกและมัน '
ฉันขอแนะนำว่าสำหรับกรณีส่วนใหญ่ที่รายการที่เชื่อมโยงทำหน้าที่เป็นการเพิ่มประสิทธิภาพที่มีประสิทธิภาพมากกว่าทางเลือกที่ตรงไปตรงมารูปแบบที่มีประโยชน์มากที่สุดมักจะเชื่อมโยงโดยลำพังเพียงต้องการตัวชี้หัวและไม่จำเป็นต้องจัดสรรหน่วยความจำ โหนดและมักจะสามารถเพียงแค่หน่วยความจำพูลจัดสรรแล้วต่อโหนด (จากอาร์เรย์ขนาดใหญ่ที่จัดสรรล่วงหน้าแล้วเช่น) นอกจากนี้แต่ละ SLL จะเก็บองค์ประกอบจำนวนเล็กน้อยในกรณีเหล่านั้นเช่นขอบที่เชื่อมต่อกับโหนดกราฟ
นอกจากนี้ยังควรคำนึงว่าเรามี DRAM จำนวนมากในทุกวันนี้ แต่นั่นเป็นหน่วยความจำชนิดที่ช้าที่สุดที่มีอยู่ เรายังคงอยู่ที่ 64 KB ต่อคอร์เมื่อมันมาถึงแคช L1 ที่มีบรรทัดแคช 64- ไบต์ ด้วยเหตุนี้การประหยัดไบต์ขนาดเล็กเหล่านี้จึงมีความสำคัญอย่างยิ่งในพื้นที่สำคัญด้านประสิทธิภาพเช่นอนุภาคซิมด้านบนเมื่อคูณหลายล้านครั้งถ้ามันหมายถึงความแตกต่างระหว่างการจัดเก็บสองเท่าของโหนดจำนวนมากลงในแคชแถวหรือไม่เช่น