Triển khai danh sách liên kết đơn trong C

Thiết kế cấu trúc nút

typedef struct Node {
    void* payload;
    struct Node* next;
} Node;
  • payload: Con trỏ kiểu void* lưu dữ liệu, cho phép linh hoạt với nhiều kiểu dữ liệu.
  • next: Con trỏ đến nút tiếp theo trong danh sách.

Thiết kế cấu trúc danh sách

typedef struct LinkedList {
    Node head;
    int length;
} LinkedList;
  • head: Nút đầu tiên (không chứa dữ liệu thực), dùng làm điểm khởi đầu.
  • length: Số lượng phần tử thực tế trong danh sách.

Khởi tạo danh sách

LinkedList* createList() {
    LinkedList* list = malloc(sizeof(LinkedList));
    if (!list) return NULL;

    list->head.payload = NULL;
    list->head.next = NULL;
    list->length = 0;
    return list;
}

Cấp phát bộ nhớ cho danh sách và khởi tạo nút gốc cùng độ dài ban đầu bằng 0.

Chèn phần tử vào vị trí chỉ định

void insertAt(LinkedList* list, int index, void* data) {
    if (!list || !data) return;

    if (index < 0 || index > list->length)
        index = list->length;

    Node* current = &list->head;
    for (int i = 0; i < index; ++i)
        current = current->next;

    Node* newNode = malloc(sizeof(Node));
    newNode->payload = data;
    newNode->next = current->next;
    current->next = newNode;

    list->length++;
}

Hàm tự động chèn vào cuối nếu vị trí không hợp lệ. Duyệt đến nút trước vị trí cần chèn, sau đó nối nút mới vào.

Duyệt danh sách

void traverse(LinkedList* list, void (*callback)(void*)) {
    if (!list) return;

    Node* current = list->head.next;
    for (int i = 0; i < list->length; ++i) {
        callback(current->payload);
        current = current->next;
    }
}

Gọi hàm callback trên từng phần tử dữ liệu, bắt đầu từ nút đầu tiên sau nút gốc.

Xóa phần tử theo vị trí

void removeAt(LinkedList* list, int index) {
    if (!list || index < 0 || index >= list->length)
        return;

    Node* prev = &list->head;
    for (int i = 0; i < index; ++i)
        prev = prev->next;

    Node* target = prev->next;
    prev->next = target->next;
    free(target);
    list->length--;
}

Tìm nút đứng trước vị trí cần xóa, cập nhật liên kết và giải phóng bộ nhớ của nút bị xóa.

Xóa phần tử theo giá trị

void removeByValue(LinkedList* list, void* value,
                   int (*equals)(void*, void*)) {
    if (!list || !value) return;

    Node* prev = &list->head;
    Node* current = prev->next;

    for (int i = 0; i < list->length; ++i) {
        if (equals(current->payload, value)) {
            prev->next = current->next;
            free(current);
            list->length--;
            return;
        }
        prev = current;
        current = current->next;
    }
}

Sử dụng hàm so sánh do người dùng cung cấp để tìm và xóa nút đầu tiên khớp giá trị.

Xóa toàn bộ danh sách

void clear(LinkedList* list) {
    if (!list) return;

    Node* current = list->head.next;
    while (current) {
        Node* next = current->next;
        free(current);
        current = next;
    }

    list->head.next = NULL;
    list->length = 0;
}

Giải phóng tuần tự từng nút dữ liệu, đặt lại con trỏ đầu và độ dài về trạng thái rỗng.

Lấy độ dài danh sách

int size(LinkedList* list) {
    return list ? list->length : -1;
}

Trả về số phần tử nếu danh sách hợp lệ, ngược lại trả về -1.

Hủy danh sách

void destroy(LinkedList* list) {
    if (!list) return;
    clear(list);
    free(list);
}

Xóa tất cả phần tử và giải phóng bộ nhớ của cấu trúc danh sách.

Thẻ: C linked-list Data-Structures void-pointer dynamic-memory

Đăng vào ngày 3 tháng 6 lúc 17:18