Viễn Đinh

Viễn Đinh

Khá Hơn 0,5% Mỗi Ngày

Cách Giải Danh Sách Liên Kết Đơn (Singly Linked List), Dể Hiểu

Bạn có biết rằng máy tính không chỉ lưu trữ dữ liệu trong các ô nhớ tĩnh? Từ nhu cầu biểu diễn và quản lý các bộ dữ liệu thay đổi liên tục, danh sách liên kết ra đời. Đây là cách mà các lập trình viên giải quyết bài toán lưu trữ linh hoạt, khi các cấu trúc như mảng chưa đủ để đáp ứng.

Định Nghĩa

Danh sách liên kết đơn (singly linked list) là một cấu trúc dữ liệu bao gồm một chuỗi các nút (node). Mỗi nút chứa hai thành phần chính: dữ liệu và một con trỏ (pointer) trỏ đến nút tiếp theo. Điều đặc biệt là nó chỉ đi theo một chiều – từ đầu đến cuối.

Hãy hình dung một chuỗi xe tải chở hàng. Mỗi xe có một container (dữ liệu) và một cái móc kéo (con trỏ) nối với xe sau. Xe cuối cùng thì không kéo ai, và đó chính là điểm kết thúc của danh sách.

So với mảng, danh sách liên kết không yêu cầu ô nhớ liên tục. Bạn không cần phải biết trước kích thước tổng thể. Thay vì thế, danh sách liên kết phát triển dần dần, từng nút một.

Nhưng, nhược điểm lớn là việc truy cập dữ liệu không nhanh bằng mảng, vì bạn phải duyệt qua từng nút từ đầu đến vị trí mong muốn. Đó là cái giá bạn phải trả cho sự linh hoạt này.

Cách Giải

Cấu trúc dữ liệu Danh Sách Liên Kết Đơn hoạt động trên nguyên tắc kết nối các nút qua con trỏ. Sau đây là các phương thức phổ biến:

Bạn thấy đó, từng phương thức đảm nhận một nhiệm vụ cụ thể, giúp bạn dễ dàng tương tác và thao tác dữ liệu. Không có nút nào độc lập; chúng hoạt động như một đội, mỗi nút phụ thuộc vào nút liền kề.

Triển Khai

class Node<T> {
  element: T;
  next: Node<T> | null;

  constructor(element: T) {
    this.element = element;
    this.next = null;
  }
}

class SinglyLinkedList<T> {
  private head: Node<T> | null;
  length: number;

  constructor() {
    this.head = null;
    this.length = 0;
  }

  add(element: T) {
    const node = new Node(element);

    if (this.head === null) {
      this.head = node;
    } else {
      let current = this.head;

      while (current.next) {
        current = current.next!;
      }

      current.next = node;
    }

    this.length++;
  }

  remove(element: T) {
    if (this.head?.element === element) {
      this.head = this.head.next;
      this.length--;
    } else {
      let prev = this.head;
      let current = this.head?.next;

      while (current) {
        if (current.element === element) {
          prev!.next = current.next;
          this.length--;
        }

        prev = current;
        current = current.next;
      }
    }
  }

  isEmpty() {
    return this.length === 0;
  }

  indexOf = (element: T) => {
    let index = 0;
    let current = this.head;

    while (current) {
      if (current.element === element) {
        return index;
      }

      index++;
      current = current.next;
    }

    return -1;
  };

  elementAt(at: number) {
    let index = 0;
    let current = this.head;

    while (current) {
      if (at === index) {
        return current.element;
      }

      index++;
      current = current.next;
    }
  }

  addAt(at: number, element: T) {
    const node = new Node(element);

    if (at === 0) {
      node.next = this.head;
      this.head = node;
      this.length++;
    } else {
      let index = 1;
      let prev = this.head;
      let current = this.head?.next;

      while (current) {
        if (at === index) {
          node.next = current;
          prev!.next = node;

          this.length++;

          return;
        }

        index++;
        prev = current;
        current = current.next;
      }
    }
  }
}

Toàn Cảnh

Danh sách liên kết nằm ở giao điểm giữa sự linh hoạt và hiệu quả. Nó là nền tảng cho nhiều cấu trúc phức tạp như danh sách liên kết kép, ngăn xếp (stack), và hàng đợi (queue).

Bạn sẽ gặp danh sách liên kết trong các thuật toán tìm kiếm và sắp xếp phức tạp. Chẳng hạn, các cấu trúc như cây nhị phân (binary tree) hoặc đồ thị (graph) đều tận dụng ý tưởng “kết nối”.

Khi bạn cần biểu diễn dữ liệu thay đổi nhanh chóng – như danh sách hàng chờ của khách hàng – danh sách liên kết trở nên vô giá. Khả năng thêm/xóa nhanh ở đầu hoặc cuối là lý do chính.

Tuy nhiên, nó không phải là cấu trúc “vạn năng”. Khi cần truy cập ngẫu nhiên dữ liệu, mảng vượt trội hơn. Lựa chọn công cụ phù hợp là chìa khóa.

Ứng Dụng

Hãy tưởng tượng bạn xây dựng một ứng dụng quản lý danh sách khách hàng. Danh sách liên kết giúp bạn thêm và xóa khách hàng dễ dàng mà không cần di chuyển toàn bộ dữ liệu.

Trong các trò chơi, danh sách liên kết có thể lưu trữ lịch sử các bước đi. Người chơi có thể quay lại bước trước đó hoặc tiến lên bước tiếp theo mà không bị rối.

Ngoài ra, hệ điều hành dùng danh sách liên kết để quản lý các tiến trình đang chạy. Nó giúp chuyển đổi giữa các nhiệm vụ một cách nhanh chóng.

Ngay cả trình duyệt của bạn cũng dùng danh sách liên kết để theo dõi lịch sử các trang web bạn đã ghé thăm. Nhấn “quay lại” là cách bạn truy cập nút trước đó trong danh sách.

Hiểu Lầm

Nhiều bạn cho rằng danh sách liên kết nhanh hơn mảng vì không cần sắp xếp lại dữ liệu khi thêm/xóa. Điều này đúng, nhưng chỉ với các thao tác thêm/xóa đơn giản.

Hiểu sai phổ biến khác là danh sách liên kết có thể thay thế mảng hoàn toàn. Thực tế, với những bài toán yêu cầu truy cập nhanh, mảng vẫn tốt hơn.

Ngoài ra, một số bạn nhầm lẫn rằng tất cả các danh sách liên kết đều giống nhau. Danh sách liên kết đơn, kép, và vòng đều có ưu và nhược điểm riêng.

Cuối cùng, nhiều người đánh giá thấp chi phí bộ nhớ của danh sách liên kết. Mỗi nút đều cần lưu trữ thêm con trỏ, và điều này có thể gây lãng phí.

Tóm Tắt

Danh sách liên kết đơn là một chuỗi các nút được liên kết qua con trỏ. Nó không yêu cầu ô nhớ liên tục, giúp bạn quản lý dữ liệu linh hoạt hơn.

Tuy nhiên, khả năng truy cập tuần tự của nó có thể là một hạn chế. Việc lựa chọn danh sách liên kết hay mảng phụ thuộc vào bài toán cụ thể.

Bạn sẽ gặp danh sách liên kết trong các ứng dụng như lịch sử duyệt web, hàng đợi, hoặc quản lý tiến trình. Nó là nền tảng của nhiều cấu trúc dữ liệu hiện đại.

Nhớ rằng, không có cấu trúc nào hoàn hảo. Đặt câu hỏi đúng – “cấu trúc nào phù hợp nhất?” – chính là cách để bạn trở thành lập trình viên giỏi.

Nguồn: Viễn Đinh - Cách Giải Danh Sách Liên Kết Đơn