hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
    • Cấu trúc dữ liệu và giải thuật
    • Lập Trình C# Cơ Bản
    • Machine Learning
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • Cấu trúc dữ liệu
  • Cấu trúc dữ liệu và giải thuật
Cấu trúc dữ liệu danh sách liên kết (LinkedList)

Cấu trúc dữ liệu danh sách liên kết (LinkedList)

  • 19-12-2024
  • Toanngo92
  • 1 Comment

LinkedList là một cấu trúc dữ liệu dạng danh sách liên kết, trong đó các phần tử được liên kết với nhau thông qua các nút (nodes). Mỗi nút chứa hai phần chính:

  1. Dữ liệu (Data): Lưu trữ giá trị thực tế của phần tử.
  2. Con trỏ (Pointer): Trỏ đến nút kế tiếp trong danh sách (hoặc nút trước nếu là danh sách liên kết đôi).

Mục lục

    • Phân loại LinkedList
    • Ưu điểm của LinkedList
    • Nhược điểm của LinkedList
    • Ứng dụng của LinkedList
  • 1. Singly Linked List (Danh sách liên kết đơn)
    • Truy cập
    • Tìm kiếm
    • Thêm
    • Xóa
  • 2. Doubly Linked List (Danh sách liên kết đôi)
    • Truy cập
    • Tìm kiếm
    • Thêm
    • Xóa
  • 3. Circular Linked List (Danh sách liên kết vòng)
    • Truy cập
    • Tìm kiếm
    • Thêm
    • Xóa
  • Tóm tắt độ phức tạp
  • So sánh thực tế
    • Phân tích sự khác biệt giữa danh sách liên kết đôi và danh sách liên kết vòng
    • 1. Khác biệt về cấu trúc
    • 2. Khác biệt về cách hoạt động
      • Điểm bắt đầu và kết thúc
      • Duyệt danh sách
      • Thao tác thêm/xóa
    • 3. Khác biệt về ứng dụng thực tế
      • Danh sách liên kết đôi:
      • Danh sách liên kết vòng:
    • 4. Điểm tương đồng về hiệu suất
    • Tóm tắt sự khác biệt
    • Khi nào chọn loại nào?

Phân loại LinkedList

Có ba loại danh sách liên kết phổ biến:

Singly Linked List (Danh sách liên kết đơn):

Ví dụ triển khai bằng python

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None  # Trỏ đến nút kế tiếp

class SinglyLinkedList:
    def __init__(self):
        self.head = None  # Điểm bắt đầu của danh sách

    def append(self, data):
        new_node = Node(data)
        if not self.head:  # Nếu danh sách trống
            self.head = new_node
            return
        current = self.head
        while current.next:  # Tìm đến nút cuối
            current = current.next
        current.next = new_node  # Thêm nút mới vào cuối

    def display(self):
        current = self.head
        while current:
            print(current.data, end=" -> ")
            current = current.next
        print("None")

# Sử dụng
sll = SinglyLinkedList()
sll.append(10)
sll.append(20)
sll.append(30)
sll.display()  # Kết quả: 10 -> 20 -> 30 -> None

Doubly Linked List (Danh sách liên kết đôi):

Ví dụ triển khai bằng python

class Node:
    def __init__(self, data):
        self.data = data
        self.prev = None  # Trỏ đến nút trước
        self.next = None  # Trỏ đến nút kế tiếp

class DoublyLinkedList:
    def __init__(self):
        self.head = None  # Điểm bắt đầu của danh sách

    def append(self, data):
        new_node = Node(data)
        if not self.head:  # Nếu danh sách trống
            self.head = new_node
            return
        current = self.head
        while current.next:  # Tìm đến nút cuối
            current = current.next
        current.next = new_node  # Gắn nút mới vào cuối
        new_node.prev = current  # Liên kết ngược về nút trước

    def display(self):
        current = self.head
        while current:
            print(current.data, end=" <-> ")
            current = current.next
        print("None")

# Sử dụng
dll = DoublyLinkedList()
dll.append(10)
dll.append(20)
dll.append(30)
dll.display()  # Kết quả: 10 <-> 20 <-> 30 <-> None

Circular Linked List (Danh sách liên kết vòng):

Ví dụ triển hkai bằng python:

class Node:
    def __init__(self, data):
        self.data = data
        self.next = None  # Trỏ đến nút kế tiếp

class CircularLinkedList:
    def __init__(self):
        self.head = None  # Điểm bắt đầu của danh sách

    def append(self, data):
        new_node = Node(data)
        if not self.head:  # Nếu danh sách trống
            self.head = new_node
            new_node.next = self.head  # Liên kết vòng
            return
        current = self.head
        while current.next != self.head:  # Tìm đến nút cuối
            current = current.next
        current.next = new_node  # Gắn nút mới vào cuối
        new_node.next = self.head  # Liên kết vòng

    def display(self):
        current = self.head
        if not current:
            print("Danh sách rỗng")
            return
        while True:
            print(current.data, end=" -> ")
            current = current.next
            if current == self.head:  # Quay lại nút đầu, dừng lại
                break
        print("(vòng về đầu)")

# Sử dụng
cll = CircularLinkedList()
cll.append(10)
cll.append(20)
cll.append(30)
cll.display()  # Kết quả: 10 -> 20 -> 30 -> (vòng về đầu)

Ưu điểm của LinkedList

  1. Chèn và xoá phần tử nhanh chóng:
    • Việc chèn/xoá không cần di chuyển các phần tử khác, chỉ cần thay đổi con trỏ.
  2. Sử dụng bộ nhớ động:
    • Không cần cấp phát trước một khối bộ nhớ cố định.
  3. Thích hợp cho cấu trúc dữ liệu phức tạp:
    • Dễ dàng triển khai các cấu trúc như hàng đợi (Queue), ngăn xếp (Stack), và đồ thị (Graph).

Nhược điểm của LinkedList

  1. Truy cập tuần tự:
    • Không thể truy cập trực tiếp phần tử (như mảng), phải duyệt tuần tự từ đầu danh sách.
  2. Tốn thêm bộ nhớ:
    • Mỗi nút cần lưu con trỏ, do đó sử dụng nhiều bộ nhớ hơn mảng.
  3. Khó khăn trong thao tác ngược (với LinkedList đơn):
    • Không thể quay lại nút trước khi không có con trỏ trỏ ngược.

Ứng dụng của LinkedList

  • Triển khai các hàng đợi và ngăn xếp.
  • Thực hiện undo/redo trong trình soạn thảo văn bản.
  • Quản lý bộ nhớ động hoặc danh sách công việc (to-do list).
  • Tạo danh sách liên kết vòng cho các ứng dụng vòng lặp (như lập lịch CPU).

Việc phân tích tiệm cận thao tác với các loại LinkedList (Singly, Doubly, Circular) sẽ dựa vào các phép toán chính như truy cập, tìm kiếm, thêm, và xóa. Tiệm cận tính toán theo độ phức tạp O().


1. Singly Linked List (Danh sách liên kết đơn)

Truy cập

  • Best/Worst case: O(n)
    • Vì phải duyệt tuần tự từ nút đầu đến nút cần truy cập, không có cách truy cập trực tiếp.
    • Với nn là số phần tử.

Tìm kiếm

  • Best case: O(1)
    • Nếu phần tử cần tìm nằm ở đầu danh sách.
  • Worst case: O(n)
    • Nếu phần tử nằm ở cuối danh sách hoặc không tồn tại.

Thêm

  • Thêm vào đầu: O(1)
    • Chỉ cần tạo nút mới và trỏ nó đến nút đầu tiên.
  • Thêm vào cuối: O(n)
    • Phải duyệt đến nút cuối cùng trước khi thêm.

Xóa

  • Xóa đầu: O(1)
    • Chỉ cần thay đổi con trỏ head trỏ đến nút thứ hai.
  • Xóa cuối hoặc giữa: O(n)
    • Phải duyệt đến phần tử trước phần tử cần xóa để cập nhật con trỏ.

Tham khảo thêm tại: https://www.geeksforgeeks.org/singly-linked-list-tutorial/


2. Doubly Linked List (Danh sách liên kết đôi)

Truy cập

  • Best/Worst case: O(n)
    • Tương tự LinkedList đơn, cần duyệt tuần tự để truy cập.

Tìm kiếm

  • Best case: O(1)
    • Nếu phần tử nằm ở đầu hoặc cuối (có thể tối ưu nếu lưu trỏ đến cuối).
  • Worst case: O(n)
    • Khi cần duyệt toàn bộ danh sách.

Thêm

  • Thêm vào đầu/cuối: O(1)
    • Dễ dàng vì có trỏ ngược (prev).
  • Thêm giữa: O(n)
    • Phải duyệt tìm vị trí cần thêm.

Xóa

  • Xóa đầu/cuối: O(1)
    • Thao tác đơn giản nhờ trỏ ngược.
  • Xóa giữa: O(n)
    • Phải duyệt đến nút trước nút cần xóa.

3. Circular Linked List (Danh sách liên kết vòng)

Truy cập

  • Best/Worst case: O(n)
    • Duyệt tuần tự như LinkedList đơn, nhưng nếu biết trước cấu trúc thì có thể tiếp tục vòng lặp.

Tìm kiếm

  • Best case: O(1)
    • Nếu phần tử cần tìm là nút đầu.
  • Worst case: O(n)
    • Phải duyệt qua toàn bộ danh sách.

Thêm

  • Thêm vào đầu/cuối: O(1)
    • Đặc biệt nhanh vì có thể tận dụng liên kết vòng, thay đổi trỏ cuối cùng trực tiếp.
  • Thêm giữa: O(n)
    • Tương tự như LinkedList đơn.

Xóa

  • Xóa đầu/cuối: O(1)
    • Dễ dàng vì cấu trúc vòng hỗ trợ.
  • Xóa giữa: O(n)
    • Phải duyệt đến vị trí cần xóa.

Tóm tắt độ phức tạp

Thao tácSingly Linked ListDoubly Linked ListCircular Linked List
Truy cậpO(n)O(n)O(n)
Tìm kiếmO(n)O(n)O(n)
Thêm đầuO(1)O(1)O(1)
Thêm cuốiO(n)O(1)O(1)
Xóa đầuO(1)O(1)O(1)
Xóa cuốiO(n)O(1)O(1)
Xóa giữaO(n)O(n)O(n)

So sánh thực tế

  1. Singly Linked List:
    • Thích hợp khi thao tác chính là thêm/xóa ở đầu danh sách.
    • Bộ nhớ tiết kiệm hơn danh sách liên kết đôi.
  2. Doubly Linked List:
    • Linh hoạt và dễ thao tác khi cần thêm/xóa ở đầu, cuối hoặc giữa danh sách.
    • Tốn thêm bộ nhớ cho con trỏ prev.
  3. Circular Linked List:
    • Phù hợp với các ứng dụng cần vòng lặp liên tục như lập lịch CPU hoặc buffer vòng (ring buffer).
    • Tối ưu tốc độ thêm/xóa ở đầu/cuối.

Phân tích sự khác biệt giữa danh sách liên kết đôi và danh sách liên kết vòng

1. Khác biệt về cấu trúc

  • Danh sách liên kết đôi:
    • Mỗi nút có hai con trỏ:
      • Một con trỏ trỏ đến nút trước (prev).
      • Một con trỏ trỏ đến nút sau (next).
    • Nút đầu (head) có con trỏ prev = None, và nút cuối (tail) có con trỏ next = None.
    • Danh sách có điểm đầu và điểm cuối rõ ràng.
    Cấu trúc: None <- Node1 <-> Node2 <-> Node3 -> None
  • Danh sách liên kết vòng:
    • Có thể là vòng đơn hoặc vòng đôi:
      • Vòng đơn: Nút cuối trỏ đến nút đầu (chỉ có con trỏ next).Vòng đôi: Nút cuối trỏ đến nút đầu và nút đầu trỏ ngược về nút cuối (cả next và prev).
      Danh sách không có điểm bắt đầu hoặc kết thúc rõ ràng khi duyệt.

2. Khác biệt về cách hoạt động

Điểm bắt đầu và kết thúc

  • Danh sách liên kết đôi:
    • Có điểm đầu (head) và điểm cuối (tail) rõ ràng.
    • Khi duyệt đến None, danh sách kết thúc.
    • Không tự động quay lại nút đầu.
  • Danh sách liên kết vòng:
    • Không có điểm kết thúc, vì nút cuối trỏ ngược về nút đầu.
    • Có thể quay vòng liên tục khi duyệt, nên cần kiểm tra điểm dừng thủ công.

Duyệt danh sách

  • Danh sách liên kết đôi:
    • Duyệt danh sách từ đầu đến cuối hoặc ngược lại từ cuối lên đầu.
    • Phù hợp khi cần truy cập hai chiều mà không yêu cầu vòng lặp.
  • Danh sách liên kết vòng:
    • Có thể duyệt tuần hoàn qua danh sách không giới hạn.
    • Thích hợp cho các ứng dụng yêu cầu xử lý lặp lại.

Thao tác thêm/xóa

  • Hiệu suất thêm/xóa ở đầu hoặc cuối tương tự nhau (O(1)O(1)).
  • Danh sách vòng có lợi thế trong việc thao tác lặp lại nhờ tính vòng lặp tự nhiên.

3. Khác biệt về ứng dụng thực tế

Danh sách liên kết đôi:

  • Phù hợp cho các ứng dụng không yêu cầu vòng lặp liên tục:
    • Trình duyệt: Quản lý lịch sử duyệt web (quay lại và tiến tới).
    • Chỉnh sửa văn bản: Undo/redo thao tác.
    • Các cấu trúc như Deque: Thêm/xóa ở cả hai đầu.

Danh sách liên kết vòng:

  • Dùng trong các ứng dụng yêu cầu xử lý vòng lặp liên tục:
    • Lập lịch CPU (Round-Robin Scheduling): Xử lý công việc lần lượt theo vòng.
    • Hàng đợi vòng (Circular Queue): Phù hợp với hệ thống lưu trữ cố định như bộ nhớ đệm (buffer).
    • Game Development: Quản lý vòng đời của các đối tượng hoặc nhân vật.

4. Điểm tương đồng về hiệu suất

Thao tácDanh sách liên kết đôiDanh sách liên kết vòng (vòng đôi)
Truy cậpO(n)O(n)O(n)O(n)
Tìm kiếmO(n)O(n)O(n)O(n)
Thêm đầu/cuốiO(1)O(1)O(1)O(1)
Xóa đầu/cuốiO(1)O(1)O(1)O(1)

=> Hiệu suất là tương đương, nhưng khác biệt ở cách sử dụng.


Tóm tắt sự khác biệt

Tiêu chíDanh sách liên kết đôiDanh sách liên kết vòng
Liên kết cuốiTrỏ đến NoneTrỏ lại nút đầu, tạo vòng
Kết thúc danh sáchCó điểm đầu và cuối rõ ràngKhông có điểm kết thúc, vòng lặp liên tục
Ứng dụng chínhUndo/redo, deque, trình duyệt lịch sửLập lịch CPU, buffer vòng, hàng đợi vòng
DuyệtDuyệt từ đầu đến cuối hoặc ngược lạiDuyệt vòng lặp liên tục

Khi nào chọn loại nào?

  • Chọn danh sách liên kết đôi:
    • Khi cần truy cập hai chiều nhưng không cần vòng lặp.
    • Thích hợp cho các ứng dụng đơn giản, tuyến tính.
  • Chọn danh sách liên kết vòng:
    • Khi ứng dụng cần xử lý liên tục hoặc quay vòng.
    • Phù hợp với các thuật toán vòng lặp hoặc tối ưu lưu trữ.

Bài viết liên quan:

Cấu trúc dữ liệu Mảng (Array)
Giới thiệu về thuật toán
Định lý thợ (Master Theorem)
Giải thuật Qui hoạch động (Dynamic Programming) 
Giải thuật chia để trị (Divide and Conquer)
Phân tích tiệm cận trong CTDL và giải thuật
Giải thuật tham lam (Greedy Algorithm)
Đệ quy trong lập trình
Thuật toán tìm kiếm nhảy – Jump Search
Thuật toán tìm kiếm nhị phân – binary search
Thuật toán tìm kiếm tuần tự – linear search
Sắp xếp trộn – Merge Sort

1 Comments

  1. Pingback: Blog nghiên cứu về lập trình, viết mã

THÊM BÌNH LUẬN Cancel reply

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

2. PHÂN TÍCH VÀ ĐẶC TẢ HỆ THỐNG

3. THIẾT KẾ HỆ THỐNG

1. TỔNG QUAN KIẾN THỨC THỰC HÀNH TRIỂN KHAI DỰ ÁN CÔNG NGHỆ THÔNG TIN

Hướng dẫn tự cài đặt n8n comunity trên CyberPanel, trỏ tên miền

Mẫu prompt tạo mô tả chi tiết bối cảnh

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×