链表基础知识

1. 推荐资源链接

2. 学习内容

2.1 链表的基础知识

链表是计算机科学中一种基础的数据结构,它由一组节点组成,每个节点包含数据和指向下一个节点的指针(或引用)。与数组不同,链表中的元素在内存中不必是连续存储的,这使得链表在某些操作上比数组更灵活。

  1. 单向链表(Singly Linked List)
    • 结构:每个节点包含两个部分:数据和指向下一个节点的指针。
    • 特点:从第一个节点开始,只能沿着指针方向逐个访问后续节点,无法逆向访问。
    • 代码示例
#include <iostream>
using namespace std;

class Node {
public:
    int data;
    Node* next;

    Node(int data) {
        this->data = data;
        this->next = nullptr;
    }
};

class SinglyLinkedList {
public:
    Node* head;

    SinglyLinkedList() {
        head = nullptr;
    }

    void append(int data) {
        Node* newNode = new Node(data);
        if (head == nullptr) {
            head = newNode;
        } else {
            Node* current = head;
            while (current->next != nullptr) {
                current = current->next;
            }
            current->next = newNode;
        }
    }

    void printList() {
        Node* current = head;
        while (current != nullptr) {
            cout << current->data << " -> ";
            current = current->next;
        }
        cout << "null" << endl;
    }
};

int main() {
    SinglyLinkedList list;
    list.append(10);
    list.append(20);
    list.append(30);
    list.printList();

    return 0;
}

  1. 双向链表(Doubly Linked List)
    • 结构:每个节点包含三个部分:数据、指向下一个节点的指针和指向上一个节点的指针。
    • 特点:可以双向遍历链表,既可以从头节点向后遍历,也可以从尾节点向前遍历。
    • 代码示例
#include <iostream>
using namespace std;

class Node {
public:
    int data;
    Node* next;
    Node* prev;

    Node(int data) {
        this->data = data;
        this->next = nullptr;
        this->prev = nullptr;
    }
};

class DoublyLinkedList {
public:
    Node* head;

    DoublyLinkedList() {
        head = nullptr;
    }

    void append(int data) {
        Node* newNode = new Node(data);
        if (head == nullptr) {
            head = newNode;
        } else {
            Node* current = head;
            while (current->next != nullptr) {
                current = current->next;
            }
            current->next = newNode;
            newNode->prev = current;
        }
    }

    void printList() {
        Node* current = head;
        while (current != nullptr) {
            cout << current->data << " <-> ";
            current = current->next;
        }
        cout << "null" << endl;
    }
};

int main() {
    DoublyLinkedList list;
    list.append(10);
    list.append(20);
    list.append(30);
    list.printList();

    return 0;
}
  1. 循环链表(Circular Linked List)
    • 结构:链表的最后一个节点指向头节点,从而形成一个环。
    • 特点:可以从任意一个节点开始进行循环遍历,适用于需要反复遍历的数据结构。
    • 代码示例(单向循环链表)
#include <iostream>
using namespace std;

class Node {
public:
    int data;
    Node* next;

    Node(int data) {
        this->data = data;
        this->next = nullptr;
    }
};

class CircularLinkedList {
public:
    Node* head;

    CircularLinkedList() {
        head = nullptr;
    }

    void append(int data) {
        Node* newNode = new Node(data);
        if (head == nullptr) {
            head = newNode;
            newNode->next = head;
        } else {
            Node* current = head;
            while (current->next != head) {
                current = current->next;
            }
            current->next = newNode;
            newNode->next = head;
        }
    }

    void printList() {
        if (head == nullptr) return;

        Node* current = head;
        do {
            cout << current->data << " -> ";
            current = current->next;
        } while (current != head);
        cout << "(head)" << endl;
    }
};

int main() {
    CircularLinkedList list;
    list.append(10);
    list.append(20);
    list.append(30);
    list.printList();

    return 0;
}

最常用的链表是:

  • 无头单向非循环链表

  • 带头双向循环链表

链表的基本操作

链表是由一系列节点连接在一起形成的结构。每个节点包含两个部分:数据域和指针域。数据域存储具体的数据,类似于数组中的元素;指针域则保存指向下一个节点的内存地址。在遍历链表时,我们通过读取当前节点的指针域找到下一个节点,并依次向下访问,从而完成增、删、改、查等基本操作。通过这种方式,链表实现了节点之间的串联,使得操作灵活且高效。

  1. 插入(Insertion)

    • 可以在链表的开头、中间或末尾插入节点。
    • 插入操作的时间复杂度通常为 O ( 1 ) O(1) O(1)(在链表头插入)或 O ( n ) O(n) O(n)(在任意位置插入)。
  2. 删除(Deletion)

    • 可以删除链表中的指定节点。
    • 删除操作的时间复杂度通常为 O ( 1 ) O(1) O(1)(删除头节点)或 O ( n ) O(n) O(n)(删除指定节点)。
  3. 查找(Search)

    • 可以遍历链表查找某个特定值。
    • 查找操作的时间复杂度为 O ( n ) O(n) O(n)
  4. 遍历(Traversal)

    • 从头节点开始,依次访问链表中的每个节点,直到结束。

链表的优缺点

优点

  • 动态大小:链表不需要预先分配固定大小的内存,可以随时扩展。

  • 插入和删除操作高效:链表在任意位置插入或删除节点时,只需要调整指针,不需要移动其他节点。

缺点

  • 访问速度较慢:链表不支持随机访问(Random Access),查找元素需要从头开始遍历。

  • 额外内存开销:每个节点除了存储数据外,还需要存储指针,占用额外的内存。

链表的应用场景

  • 实现堆栈和队列:链表可以轻松实现堆栈(Stack)和队列(Queue),并支持动态调整大小。

  • 符号表和字典:在哈希表中,链表常用于处理冲突(例如拉链法)。

  • 内存管理:在操作系统中,链表常用于管理空闲内存块的分配与回收。

2.2 链表的相关技巧

相关视频:ACM 金牌选手教如何做链表。力扣 No.61 旋转链表,真·动画教编程,适合语言初学者或编程新人。_哔哩哔哩_bilibili

  1. 初始化一个根节点,指向链表头

  2. 同时把最后一个节点指向的空指针也标注出来

在这里插入图片描述
在这里插入图片描述

链表的主要思路是:找到关键的指针

  • 16
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值