- Apter Trees ใน C++
- Tree ที่แสดงโครงสร้างอย่างเรียบง่ายโดยใช้เพียงเวกเตอร์สองชุดคือ [ค่าของโหนด, ดัชนีของโหนดแม่)
- Tree ส่วนใหญ่มักอิมพลีเมนต์แบบ binary tree โดยแต่ละโหนดจะมีค่าของตัวเองและพอยน์เตอร์ไปยังโหนดลูกซ้าย/ขวา
- โครงสร้างข้อมูลแบบนี้มักต้องอิมพลีเมนต์ด้วย recursion และอาจช้าลงได้จากพฤติกรรมของแคชและการเรียก
malloc() บ่อยครั้ง
- แนวคิดว่าใครเป็นผู้ "ครอบครอง" tree node อาจซับซ้อนขึ้นในซอฟต์แวร์แบบหลายเลเยอร์
- Apter tree เร็วกว่ามาก เข้าใจเหตุผลได้ง่ายกว่า และอิมพลีเมนต์ได้ง่ายกว่า
วิธีการทำงาน
- อิมพลีเมนต์ด้วยอาร์เรย์สองชุดที่มีขนาดเท่ากัน
- เวกเตอร์ (อาร์เรย์) ของข้อมูล
d
- เวกเตอร์ของดัชนีโหนดแม่
p โดยดัชนีของเวกเตอร์ d ถูกใช้เป็นคีย์ c
- บ่อยครั้งคีย์/ดัชนี
c จะเป็นชนิดจำนวนเต็ม
- ถ้า Coco เป็นแม่ของ Molly และ Arca และ Arca มีลูกชื่อ Cricket โครงสร้างจะเป็นดังนี้
tree.d = ["Coco", "Molly", "Arca","Cricket"]
tree.p = [0,0,0,2]
- โหนดที่มี parent เป็น 0 และมีคีย์เป็น 0 คือ root node (Apter tree อาจกำหนดให้ต้องมี root node เสมอ หรือใช้ -1 เพื่อหมายถึง "ไม่มีโหนดแม่" แต่ในที่นี้จะขอข้ามไป)
- คอมพิวเตอร์จัดการเวกเตอร์ได้รวดเร็วมาก เร็วกว่าการคำนวณพอยน์เตอร์อย่างมาก ดังนั้นการเปรียบเทียบ Big-O notation ของอัลกอริทึมจึงแทบไม่มีความหมายในทางปฏิบัติ
ทำไมจึงสำคัญ
- วิธีอิมพลีเมนต์นี้เป็นหนึ่งในแนวทางทำ tree ที่สง่างามที่สุดเท่าที่ผู้เขียนเคยเห็น
- หากใช้ไลบรารีสำหรับการดำเนินการกับเวกเตอร์ที่เหมาะสม จะเข้าใจง่ายและตามหาบั๊กได้ง่าย
- ด้วยความเรียบง่าย จึงนำไปปรับใช้กับกรณีการใช้งานอื่น ๆ ได้ง่าย
- สามารถวนซ้ำค่าต่าง ๆ ได้อย่างรวดเร็วโดยไม่ต้องสนใจเวกเตอร์ดัชนีโหนดแม่ ซึ่งคล้ายกับ Deep Map ที่ได้มาแบบฟรี ๆ
- เป็นมิตรกับ GPU และใช้งานได้ง่ายในสภาพแวดล้อมแบบ embedded
- สามารถดูแลความปลอดภัยได้ง่ายโดยจำกัดไม่ให้ขนาดของเวกเตอร์โตเกินค่าที่กำหนด
ที่มา
- ผู้เขียนกำลังพยายามหาว่าใครเป็นผู้คิดค้นเทคนิคนี้ และคาดว่าน่าจะมีชื่อเรียกอยู่แล้วตั้งแต่ยุคที่แนวคิดแบบ vector-oriented แพร่หลายในช่วงทศวรรษ 1960 และ 1970
- ผู้เขียนเห็นคำอธิบายที่สมบูรณ์ครั้งแรกจาก Apter แต่แนวคิดนี้ก็มีการบันทึกไว้อย่างกว้างขวางใน K3 เช่นกัน
- APL อิมพลีเมนต์ tree แบบดั้งเดิม แต่ใช้เทคนิคคล้ายกันกับ vector graph
- ผู้ใช้ J ก็คุ้นเคยกับแนวคิดนี้เช่นกัน และมีคำอธิบายเกี่ยวกับการอิมพลีเมนต์ tree ในภาษา J บน Rosetta Code
- John Earnest อธิบายการอิมพลีเมนต์ vector tree อย่างละเอียดกว่า รวมถึงแนวทางแบบ "offset index" และการจัดการรายการที่ถูกลบ
- แนวทางที่ซับซ้อนกว่านั้นคือการติดตามความลึกของแต่ละรายการ
การอิมพลีเมนต์ tree แบบทั่วไปอื่น ๆ
- มีทั้งการอิมพลีเมนต์ tree ของเคอร์เนล FreeBSD, tree ของ klib, tree class ของ Ruby และ declarative tree class ของ Python เป็นต้น
- สิ่งเหล่านี้ไม่ได้ทำงานแบบเดียวกับ Apter tree และบางแบบก็มีขนาดใหญ่กว่ามากเพราะพยายามทำให้เป็นทั่วไป
สถานะของโค้ดนี้
- เป็นความพยายามอิมพลีเมนต์สิ่งนี้เพื่อใช้เรียนรู้ C++17
- ยังไม่พร้อมสำหรับการใช้งานจริง และผู้เขียนยังต้องเรียนรู้ C++ เพิ่มอีกมาก
ความเห็นของ GN⁺
- Apter Trees ช่วยทำให้โครงสร้าง tree แบบเดิมที่ซับซ้อนเรียบง่ายลง และทำให้การจัดการข้อมูลทำได้รวดเร็วและมีประสิทธิภาพ
- การอิมพลีเมนต์ tree บนพื้นฐานของเวกเตอร์ช่วยลด memory overhead และอาจเพิ่มประสิทธิภาพได้ผ่านการเข้าถึงแบบเชิงเส้น
- บทความนี้ชวนให้เห็นแนวทางใหม่ที่น่าสนใจต่อการออกแบบโครงสร้างข้อมูลในงานวิศวกรรมซอฟต์แวร์
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
first childและnext siblingนอกจากนี้ยังแนะนำให้ปรับโครงสร้างข้อมูลเพื่อรองรับงานที่ต้องการmallocและเพิ่ม data locality ลองใช้การอิมพลีเมนต์ต้นไม้แบบดั้งเดิมที่ใช้ node poolhandleหรือindex-handleและบอกว่าวิธีแทนต้นไม้แบบนี้ชวนให้นึกถึงโครงสร้างข้อมูลคลาสสิกอย่าง heap และ disjoint setpointerชนิดหนึ่งได้ และเหตุผลที่การอิมพลีเมนต์ต้นไม้แบบดั้งเดิมต้องใช้mallocก็เพราะความจำเป็นในการเพิ่มหรือลบโหนดแบบไดนามิก หากขนาดของต้นไม้มีขีดจำกัดและไม่ได้ลบบ่อย การอิมพลีเมนต์แบบอาร์เรย์ก็อาจเหมาะสม