บทที่ 6: ลิงค์ลิสต์ (Linked List)

วัตถุประสงค์

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

เปรียบเทียบ Linked Lists กับ Array -->> Top
• Linked Lists
Placeholder image

o เก็บข้อมูลแบบไม่ต่อเนื่อง เก็บไว้ที่ไหนก็ได้ในหน่วยความจำ
o ใช้หน่วยความจำตามข้อมูลที่มีอยู่ สามารถลบออกได้ตามต้องการ
o การเพิ่มหรือลบข้อมูล สามารถทำได้อย่างรวดเร็ว
• Array
Placeholder image

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

ลิงค์ลิสต์ถือเป็น Abstract Data Type (ADT) ชนิดหนึ่ง เพราะเป็นโครงสร้างข้อมูลที่ประกอบด้วยข้อมูลและวิธีการดำเนินการกับข้อมูลนั้นๆ ได้ทุกชนิด เช่นตัวเลข ตัวอักษร สตริง เรคคอร์ด ตัวอย่างโครงสร้างข้อมูลที่เป็น ADT เช่น ลิสต์ (lists) สแตค (stacks) ต้นไม้ (trees) ตารางแฮช (hash table) คิวแบบมีเงื่อนไข (Priority queue or heap) และกราฟ (graphs) เป็นต้น ส่วนตัวอย่างวิธีดำเนินการกับข้อมูล เช่น เพิ่ม (insert) ลบ (delete) ค้นหา (find) แก้ไข (edit) พิมพ์ (print) push pop enque และ deque เป็นต้น

โครงสร้างของลิงค์ลิสต์ -->> Top

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

Placeholder image
ประเภทของลิงค์ลิสต์
• Singly Linked Lists (ลิงค์ลิสต์เดี่ยว) แต่ละโหนดเก็บตัวชี้ที่ชี้ไปยังโหนดถัดไป (next)
Placeholder image
• Doubly Linked List (ลิงค์ลิสต์คู่)

แต่ละโหนดเก็บตัวชี้ที่ชี้ไปยังโหนดถัดไป (next) และพอยเตอร์ที่ชี้ไปยังโหนดก่อนหน้า (Previous) มีประโยชน์ในการค้นหาข้อมูลแบบสองทิศทาง ทั้งข้างหน้าและข้างหลังโดยไม่จำเป็นต้องเริ่มจากโหนดแรก ใช้หน่วยความจำเพิ่มขึ้น และต้องสลับตัวชี้ในการเพิ่มและลบโหนดมากขึ้น แต่การค้นหาและลบโหนดทำได้ง่ายและรวดเร็ว

Placeholder image


• Circular Linked List (ลิงค์ลิสต์วงกลม)

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

Placeholder image
การสร้างและใช้งาน Singly Linked Lists (ลิงค์ลิสต์เดี่ยว) -->> Top
• ต้องสร้างโหนดขึ้นมาก่อนโดยใช้โครงสร้างข้อมูลแบบ class
• เพิ่มสมาชิกของโหนดตามต้องการ เพื่อความสะดวกควรกำหนดให้โหนดมีสมาชิกแค่ 2 ตัวคือ element กับ next
• ถ้า element ประกอบด้วยข้อมูลหลายๆแบบ ก็ให้สร้าง element ขึ้นมาโดยใช้โครงสร้างข้อมูลแบบ class เช่นเดียวกัน
• ใช้ new ( ) เพื่อสร้างลิงค์ลิสต์ในหน่วยความจำ
• ตัวอย่างลิงค์ลิสต์เดี่ยวที่เก็บตัวอักษร จะเห็นว่าแต่ละโหนดมีพอยเตอร์ตัวเดียวเท่านั้น

Placeholder image
การสร้างโหนดและลิงค์ลิสต์
ถ้าเราต้องการสร้างโหนดสำหรับเก็บข้อมูลชนิดใดๆ ก็ให้กำหนดรูปแบบของโหนดเป็น AnyType ดังนี้

Placeholder image
Lists Operation การดำเนินการกับลิงค์ลิสต์
Insert: การเพิ่มโหนดในลิงค์ลิสต์ ต้องสร้างโหนดใหม่ แล้วใส่เข้าไปในตำแหน่งที่ต้องการ

Placeholder image
โหนดหัว (Header node)

ในการเพิ่มและลบโหนดแรก ไม่สามารถทำได้โดยวิธีการปกติ สามารถแก้ปัญหาโดยใช้โหนดหัวเป็นโหนดแรก เพื่อให้โหนดจริงโหนดแรกมีโหนดข้างหน้า ทำให้ทุกโหนดสามารถเพิ่มและลบโดยใช้วิธีเดียวกันได้ ส่วนในการค้นหา ก็จะเริ่มจากโหนดจริงโหนดแรก (ข้ามโหนดหัวไป) การใช้โหนดหัวทำให้สามารถเพิ่มและลบลิงค์ลิสต์ทางด้านหน้าได้อย่างสะดวกและรวดเร็วด้วย Big O = O(1)

Placeholder image
โปรแกรมสร้างและจัดการกับลิงค์ลิสต์ -->> Top
Placeholder image

ในการสร้างลิงค์ลิสต์เดี่ยว ต้องสร้างคลาส ListNode ที่มีสมาชิกเป็น element และ next โดย element ใช้เก็บข้อมูลใดๆด้วยชนิด AnyType ส่วน next ใช้เก็บตัวชี้ไปยังโหนดถัดไป สังเกตว่าตัวชี้จะเป็นชนิดเดียวกับลิสต์คือ ListNode

Placeholder image
Insert List Node -->> Top
Placeholder image
Big O Insert: O(1)
Remove List Node -->> Top
Placeholder image
Placeholder image
Placeholder image
Placeholder image

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

เราไม่สามารถไปยังลิสต์ตัวที่ n โดยไม่ผ่านสมาชิกตัวที่ 1 ถึง n-1 ซึ่งแตกต่างกับอาร์เรย์ ที่สามารถอ้างถึงสมาชิกตัวใดๆ ในลิสท์นั้นได้เลยด้วยตำแหน่งของอาร์เรย์

ตัวอย่างลิสต์เก็บ Address Book -->> Top
สร้างลิงค์ลิสต์สำหรับเก็บสมุดโทรศัพท์ซึ่งประกอบด้วยชื่อ และหมายเลขโทรศัพท์

Placeholder image
Placeholder image
Placeholder image

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

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

Placeholder image
การวิเคราะห์ค่า Big O ของ Linked List
การเพิ่มข้อมูลในลิสต์แบบใช้โหนดหัว มีการทำงานครั้งเดียว ดังนั้นค่า Big O คือ O(1)
การค้นหาข้อมูลในลิสต์ ต้องค้นหาทุกตัวจนกว่าจะเจอ ดังนั้นค่า Big O คือ O(N)
การลบข้อมูลในลิสต์ ต้องค้นหาทุกตัวจนกว่าจะเจอ ดังนั้นค่า Big O คือ O(N)

สรุป -->> Top
• ลิงค์ลิสต์คือโครงสร้างข้อมูลที่ใช้เก็บข้อมูลทั่วไปคล้ายกับอาร์เรย์แต่ยืดหยุ่นและมีประสิทธิภาพมากกว่า โดยแต่ละโหนดจะเก็บในหน่วยความจำที่ว่างๆ และเชื่อมต่อกันด้วยตัวชี้ และไม่จำเป็นต้องจองหน่วยความจำล่วงหน้า
• ข้อมูลใหม่ที่เก็บในลิสต์ จะเก็บด้านหน้า ด้านหลัง หรือตำแหน่งใดๆในลิสต์ก็ได้ แต่ถ้าใช้โหนดหัวก็จะเก็บข้อมูลใหม่ด้านหน้าเท่านั้น
• การดำเนินการของลิสต์คือ Insert, Delete, Find
• การลบลิสต์ทำได้ง่ายกว่าอาร์เรย์ และเมื่อลิสต์ถูกลบ หน่วยความจำจะคืนมาในระบบเพื่อใช้งานอื่นๆต่อไป

2020. mnet50.com