โครงสร้างภายในของ LinkedList
สำรวจโครงสร้างโหนดแบบเชื่อมโยงสองทิศทางของ LinkedList และลักษณะความซับซ้อนด้านเวลา
โครงสร้างภายในของ LinkedList เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
โครงสร้างภายในของ LinkedList
LinkedList ของ Java เป็นรายการเชื่อมโยงสองทิศทาง: แต่ละโหนดเก็บการอ้างอิงไปยังโหนดก่อนหน้าและถัดไป รวมถึงค่าขององค์ประกอบนั้น ต่างจาก ArrayList ตรงที่ไม่มีอาร์เรย์เบื้องหลัง แต่จัดสรรหน่วยความจำแยกสำหรับแต่ละโหนด
class Node<T> {
T data;
Node<T> prev;
Node<T> next;
Node(T data) { this.data = data; }
}ลักษณะความซับซ้อนด้านเวลา
ลักษณะด้านประสิทธิภาพของ LinkedList แตกต่างจาก ArrayList อย่างมาก:
- addFirst / addLast: O(1)
- get(ดัชนี): O(n) — ต้องท่องผ่านจากหัวหรือท้าย
- remove(ดัชนี): O(n) เพื่อค้นหา จากนั้น O(1) เพื่อนำออกจากการเชื่อมโยง
- การท่องผ่านด้วยตัววนซ้ำ: O(n)
ใช้ LinkedList เมื่อต้องเพิ่มรายการที่หัวหรือท้ายบ่อยครั้ง ไม่ใช่เมื่อต้องการการเข้าถึงแบบสุ่ม
การสร้างและท่องผ่าน LinkedList
การสร้าง LinkedList และการวนซ้ำใช้ List interface เดียวกับที่คุณรู้จักอยู่แล้ว ความแตกต่างอยู่ที่โครงสร้างภายใน
import java.util.LinkedList;
LinkedList<String> list = new LinkedList<>();
list.add("Alice");
list.add("Bob");
list.add("Carol");
for (String name : list) {
System.out.println(name);
}
System.out.println("First: " + list.getFirst()); // Alice
System.out.println("Last: " + list.getLast()); // CaroladdFirst, addLast, removeFirst, removeLast
LinkedList มีการดำเนินการกับหัวและท้ายที่ ArrayList ไม่สามารถทำได้อย่างมีประสิทธิภาพ:
LinkedList<Integer> nums = new LinkedList<>();
nums.addLast(10); // [10]
nums.addLast(20); // [10, 20]
nums.addFirst(5); // [5, 10, 20]
System.out.println(nums.removeFirst()); // 5 → [10, 20]
System.out.println(nums.removeLast()); // 20 → [10]การถอดการเชื่อมโยงโหนด: ลบแบบ O(1) หลังค้นพบ
เมื่อคุณมีการอ้างอิงไปยังโหนดแล้ว (ผ่านตัววนซ้ำ) การนำออกจะใช้เวลา O(1) เพราะต้องอัปเดตเฉพาะตัวชี้ไปยังโหนดก่อนหน้าและถัดไปเท่านั้น — ไม่มีการเลื่อนองค์ประกอบเหมือนใน ArrayList
import java.util.*;
LinkedList<String> tasks = new LinkedList<>(List.of("A","B","C","D"));
Iterator<String> it = tasks.iterator();
while (it.hasNext()) {
String t = it.next();
if (t.equals("B") || t.equals("D")) {
it.remove(); // O(1) unlink
}
}
System.out.println(tasks); // [A, C]ค่าใช้หน่วยความจำเมื่อเทียบกับ ArrayList
แต่ละโหนดของ LinkedList มีการอ้างอิงเพิ่มเติมสองรายการ (โหนดก่อนหน้าและถัดไป) รวมถึงการอ้างอิงไปยังองค์ประกอบ — ประมาณ 48 ไบต์ต่อรายการบน JVM แบบ 64 บิต ส่วน ArrayList เก็บเพียงการอ้างอิงไปยังองค์ประกอบ (8 ไบต์) ในอาร์เรย์ที่ต่อเนื่องกัน
สำหรับชุดข้อมูลขนาดใหญ่ที่เน้นการอ่าน ArrayList มักใช้แคชได้มีประสิทธิภาพกว่าและใช้หน่วยความจำน้อยกว่า
การดำเนินการของคิวสองทาง: สแตกและคิว
LinkedList ใช้งาน Deque interface ทำให้ใช้ได้ทั้งเป็นสแตกและคิว
import java.util.LinkedList;
import java.util.Deque;
// As a Queue (FIFO)
Deque<String> queue = new LinkedList<>();
queue.offer("first");
queue.offer("second");
System.out.println(queue.poll()); // first
// As a Stack (LIFO)
Deque<String> stack = new LinkedList<>();
stack.push("bottom");
stack.push("top");
System.out.println(stack.pop()); // topภาพรวมของ PriorityQueue
PriorityQueue คือคิวที่ใช้ฮีป โดยองค์ประกอบที่เล็กที่สุด (ตามลำดับธรรมชาติหรือตัวเปรียบเทียบ) จะถูกนำออกจากคิวก่อนเสมอ โดย NOT ใช้รายการเชื่อมโยงเป็นโครงสร้างเบื้องหลัง แต่ใช้อาร์เรย์ฮีปแบบทวิภาค
import java.util.PriorityQueue;
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(40);
pq.offer(10);
pq.offer(25);
System.out.println(pq.poll()); // 10 (smallest)
System.out.println(pq.poll()); // 25
System.out.println(pq.poll()); // 40PriorityQueue พร้อมตัวเปรียบเทียบแบบกำหนดเอง
ส่ง Comparator เพื่อกลับลำดับหรือเรียงตามฟิลด์ที่กำหนดเอง:
import java.util.*;
record Task(String name, int priority) {}
PriorityQueue<Task> tasks = new PriorityQueue<>(
Comparator.comparingInt(Task::priority).reversed() // highest first
);
tasks.offer(new Task("Low", 1));
tasks.offer(new Task("High", 10));
tasks.offer(new Task("Med", 5));
while (!tasks.isEmpty()) {
System.out.println(tasks.poll().name());
}
// High, Med, Lowการเลือก LinkedList หรือ ArrayList
หลักทั่วไป:
- ใช้ ArrayList สำหรับการเข้าถึงแบบสุ่ม การวนซ้ำ และสถานการณ์ส่วนใหญ่
- ใช้ LinkedList เมื่อต้องเพิ่มหรือนำรายการออกจากปลายทั้งสองด้านบ่อยครั้งด้วย O(1) และไม่ต้องเข้าถึงด้วยดัชนี
- ใช้ PriorityQueue เมื่อต้องประมวลผลตามลำดับ เช่น การจัดตารางงานหรืออัลกอริทึมไดก์สตรา
ข้อผิดพลาดที่พบบ่อย
หลีกเลี่ยงการเรียก get(i) ในลูปบน LinkedList — เพราะใช้เวลารวม O(n²):
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 10000; i++) list.add(i);
// BAD: O(n^2) — each get(i) traverses from head
for (int i = 0; i < list.size(); i++) {
int val = list.get(i); // slow!
}
// GOOD: O(n) — use iterator
for (int val : list) {
// process val
}ตรวจสอบความเข้าใจอย่างรวดเร็ว
การดำเนินการใดของ LinkedList ที่ใช้เวลา O(1) โดยไม่ขึ้นกับขนาดรายการ
สรุป: LinkedList และคิวสองทาง
ประเด็นสำคัญ:
- LinkedList เป็นรายการเชื่อมโยงสองทิศทางที่ดำเนินการกับหัวและท้ายได้ใน O(1)
- การเข้าถึงแบบสุ่ม (การใช้ get/set ตามดัชนี) ใช้เวลา O(n)
- ใช้งาน Deque ได้ จึงใช้เป็นสแตกหรือคิวได้
- PriorityQueue ให้การประมวลผลตามลำดับของฮีป
- ควรเลือก ArrayList สำหรับกรณีส่วนใหญ่ ส่วน LinkedList เหมาะกับการเปลี่ยนแปลงที่หัวหรือท้ายบ่อยครั้ง
คำถามที่พบบ่อย
บทเรียน “โครงสร้างภายในของ LinkedList” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “โครงสร้างภายในของ LinkedList” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “โครงสร้างภายในของ LinkedList”
สำรวจโครงสร้างโหนดแบบเชื่อมโยงสองทิศทางของ LinkedList และลักษณะความซับซ้อนด้านเวลา คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “โครงสร้างภายในของ LinkedList” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- โครงสร้างภายในของ LinkedList
- การทำงานของ Deque: สแตกและคิว
- ข้อแลกเปลี่ยนระหว่าง LinkedList กับ ArrayList
- PriorityQueue สำหรับการประมวลผลตามลำดับ