📜  链表 |第一套(介绍)(1)

📅  最后修改于: 2023-12-03 15:42:07.851000             🧑  作者: Mango

链表 |第一套(介绍)

简介

链表 (Linked List) 是一种数据结构,它由一系列节点组成。每个节点包含一个数据元素和一个指向下一个节点的指针。链表的头节点是第一个节点,尾节点是最后一个节点,它们分别指向 NULL 值。

常见的链表有单向链表、双向链表和循环链表。

链表的操作包括插入、删除、查找等,其在内存中的存储结构灵活,可以动态地分配内存空间,逐一将数据结点按照链式链接起来,因而解决了数组大小固定的缺陷。

链表的优缺点分别如下:

优点:
  1. 链表空间分配灵活,可以动态地分配内存。
  2. 链表可以逐一将数据结点按照链式链接起来,因而解决了数组大小固定的缺陷。
  3. 在链表中,数据元素的插入和删除操作方便,时间复杂度与链表长度无关。
缺点:
  1. 链表的存储空间比较大,因为需要存储指针信息。
  2. 链表的随机访问效率比较低,因为需要从头节点开始一步步遍历到指定的节点。
单向链表

单向链表是链表中最简单的一种类型,其定义如下:

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

单向链表只有一个指针变量 next,它记录下一个节点的地址。

单向链表的插入和删除方法:

// 在位置pos插入节点node
ListNode* insertNode(ListNode* head, ListNode* node, int pos) {
    if (pos == 0) {
        node->next = head;
        return node;
    }

    ListNode* curr = head;
    while (curr && pos > 1) {
        curr = curr->next;
        pos--;
    }

    if (curr) {
        node->next = curr->next;
        curr->next = node;
    }

    return head;
}

// 删除值为val的节点
ListNode* deleteNode(ListNode* head, int val) {
    ListNode* dummy = new ListNode(-1);
    dummy->next = head;
    ListNode* curr = dummy;
    while (curr->next) {
        if (curr->next->val == val) {
            ListNode* tmp = curr->next;
            curr->next = tmp->next;
            delete tmp;
            break;
        } else {
            curr = curr->next;
        }
    }

    head = dummy->next;
    delete dummy;
    return head;
}
双向链表

双向链表增加了一个指针变量 prev,它记录上一个节点的地址。

双向链表的定义如下:

struct ListNode {
    int val;
    ListNode* prev;
    ListNode* next;
    ListNode(int x) : val(x), prev(nullptr), next(nullptr) {}
};

双向链表的插入和删除方法:

// 在位置pos插入节点node
ListNode* insertNode(ListNode* head, ListNode* node, int pos) {
    if (pos == 0) {
        node->next = head;
        if (head) head->prev = node;
        return node;
    }

    ListNode* curr = head;
    while (curr && pos > 1) {
        curr = curr->next;
        pos--;
    }

    if (curr) {
        node->next = curr->next;
        node->prev = curr;
        if (curr->next) curr->next->prev = node;
        curr->next = node;
    }

    return head;
}

// 删除值为val的节点
ListNode* deleteNode(ListNode* head, int val) {
    ListNode* dummy = new ListNode(-1);
    dummy->next = head;
    if (head) head->prev = dummy;

    ListNode* curr = dummy;
    while (curr->next) {
        if (curr->next->val == val) {
            ListNode* tmp = curr->next;
            curr->next = tmp->next;
            if (tmp->next) tmp->next->prev = curr;
            delete tmp;
            break;
        } else {
            curr = curr->next;
        }
    }

    head = dummy->next;
    if (head) head->prev = nullptr;
    delete dummy;
    return head;
}
循环链表

循环链表和单向链表、双向链表的区别在于尾节点指向头节点。

循环链表的定义如下:

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

循环链表的插入和删除方法与单向链表相同。