0Pricing
Java Academy · บทเรียน

โครงสร้างภายในของ 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());  // Carol

addFirst, 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()); // 40

PriorityQueue พร้อมตัวเปรียบเทียบแบบกำหนดเอง

ส่ง 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. โครงสร้างภายในของ LinkedList
  2. การทำงานของ Deque: สแตกและคิว
  3. ข้อแลกเปลี่ยนระหว่าง LinkedList กับ ArrayList
  4. PriorityQueue สำหรับการประมวลผลตามลำดับ
← กลับไปที่ Java Academy