รายการที่เชื่อมโยงควรมีตัวชี้หางหรือไม่?


11

ความเข้าใจของฉัน ...

ข้อดี:

  • การแทรกท้ายคือ O (1) แทน O (N)
  • หากรายการนั้นเป็น Doubly Linked List การลบออกจากจุดสิ้นสุดคือ O (1) แทน O (N)

ข้อด้อย:

  • จะขึ้นเป็นจำนวนเล็กน้อยของหน่วยความจำเสริม: 4-8 ไบต์
  • ผู้ดำเนินการจะต้องติดตามหาง

เมื่อมองถึงข้อดีและข้อเสียเหล่านี้ฉันไม่สามารถเห็นได้ว่าเหตุใดรายการที่เชื่อมโยงจะหลีกเลี่ยงการใช้ตัวชี้หาง มีบางอย่างที่ฉันขาดหายไปหรือไม่?


1
ตัวชี้หาง 4-8 ไบต์ (ขึ้นอยู่กับระบบ 32 หรือ 64 บิต)
ประหลาดวงล้อ

1
ฟังดูเหมือนคุณได้สรุปแล้ว
Robert Harvey

@RobertHarvey ฉันกำลังศึกษาโครงสร้างข้อมูลตอนนี้และฉันไม่ทราบว่าแนวทางปฏิบัติที่ดีที่สุดคืออะไร ดังนั้นสิ่งที่ฉันเขียนคือการแสดงผลของฉัน แต่สิ่งที่ฉันถามคือถ้ามันถูกต้อง แต่ขอขอบคุณสำหรับการชี้แจง!
Adam Zerner

7
"วิธีปฏิบัติที่ดีที่สุด" มียาเสพติดของมวลชน เฉลิมฉลองความจริงที่ว่าคุณยังมีความสามารถในการคิดด้วยตนเอง
Robert Harvey

ขอบคุณสำหรับลิงค์ @RobertHarvey - ฉันรักจุดนั้น! ฉันใช้แนวทางการประหยัดค่าใช้จ่ายที่มีลักษณะเฉพาะของสถานการณ์
Adam Zerner

คำตอบ:


7

คุณถูกต้องตัวชี้ท้ายไม่เคยเจ็บและสามารถช่วยได้ อย่างไรก็ตามมีสถานการณ์ที่ไม่ต้องการตัวชี้หางเลย

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


9

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


3
คุณจะอธิบายได้ไหมว่าทำไมพวกเขาถึงไม่ยอมทนและไม่อาจเปลี่ยนแปลงได้
Adam Zerner

กรุณาเพิ่มความกังวลเรื่องแคช
Basilevs

ดูตัวอย่างจากคำถามนี้ หากคุณทำงานจากหัวของรายการเท่านั้นและมันไม่เปลี่ยนรูปคุณสามารถแบ่งปันส่วนท้ายได้ หากคุณใช้ตัวชี้หางคุณจะไม่สามารถใช้เทคนิคนี้ในการแบ่งปันและรักษาความไม่สามารถเปลี่ยนแปลงได้
Karl Bielefeldt

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

0

ฉันไม่ค่อยใช้ตัวชี้หางสำหรับรายการที่เชื่อมโยงและมักจะใช้รายการที่เชื่อมโยงเดี่ยว ๆ บ่อยครั้งที่รูปแบบการแทรกและการเอาออกแบบกองซ้อน - เหมือนแบบกด / ป๊อป เป็นเพราะในกรณีการใช้งานทั่วไปของฉันตัวชี้ส่วนท้ายนั้นมีราคาแพงเช่นเดียวกับการสร้างรายการที่เชื่อมโยงโดยลำพังเป็นรายการที่เชื่อมโยงเป็นสองเท่ามีราคาแพง

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

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