每日一练-单链表C++实现

链表(Linked List)详解

基本概念

链表是一种线性数据结构,由一系列节点(Node)组成,每个节点包含:

  1. 数据域:存储实际数据
  2. 指针域:存储指向下一个节点的地址

与数组的连续存储不同,链表的节点在内存中是非连续存储的,通过指针链接在一起。


单链表(Singly Linked List)特点

  1. 单向链接:每个节点只有一个指针指向后继节点
  2. 头指针:指向链表中的第一个节点
  3. 尾节点:最后一个节点的指针指向 nullptr
  4. 时间复杂度
    • 插入/删除:O(1)(已知位置时)
    • 随机访问:O(n)
    • 查找:O(n)

C++ 单链表完整实现

#include <iostream>
using namespace std;

// 链表节点类
class Node {
public:
    int data;       // 数据域
    Node* next;     // 指向下一节点的指针

    Node(int val) : data(val), next(nullptr) {}
};

// 单链表类
class LinkedList {
private:
    Node* head;     // 头指针

public:
    // 构造函数:初始化空链表
    LinkedList() : head(nullptr) {}

    // 析构函数:释放所有节点内存
    ~LinkedList() {
        Node* current = head;
        while (current) {
            Node* next = current->next;
            delete current;
            current = next;
        }
        head = nullptr;
    }

    // 在头部插入新节点
    void insertAtHead(int val) {
        Node* newNode = new Node(val);
        newNode->next = head;
        head = newNode;
    }

    // 在尾部插入新节点
    void insertAtTail(int val) {
        Node* newNode = new Node(val);
        
        if (!head) {
            head = newNode;
            return;
        }
        
        Node* current = head;
        while (current->next) {
            current = current->next;
        }
        current->next = newNode;
    }

    // 在指定位置插入节点
    void insertAtIndex(int index, int val) {
        if (index < 0) return;
        
        if (index == 0) {
            insertAtHead(val);
            return;
        }
        
        Node* newNode = new Node(val);
        Node* current = head;
        
        // 移动到插入位置的前一个节点
        for (int i = 0; i < index - 1 && current; ++i) {
            current = current->next;
        }
        
        if (!current) return;  // 索引超出范围
        
        newNode->next = current->next;
        current->next = newNode;
    }

    // 删除指定值的节点
    void deleteByValue(int val) {
        if (!head) return;
        
        if (head->data == val) {
            Node* temp = head;
            head = head->next;
            delete temp;
            return;
        }
        
        Node* current = head;
        while (current->next) {
            if (current->next->data == val) {
                Node* temp = current->next;
                current->next = temp->next;
                delete temp;
                return;
            }
            current = current->next;
        }
    }

    // 删除指定位置的节点
    void deleteByIndex(int index) {
        if (!head || index < 0) return;
        
        if (index == 0) {
            Node* temp = head;
            head = head->next;
            delete temp;
            return;
        }
        
        Node* current = head;
        for (int i = 0; i < index - 1 && current; ++i) {
            current = current->next;
        }
        
        if (!current || !current->next) return;
        
        Node* temp = current->next;
        current->next = temp->next;
        delete temp;
    }

    // 查找节点是否存在
    bool contains(int val) {
        Node* current = head;
        while (current) {
            if (current->data == val) return true;
            current = current->next;
        }
        return false;
    }

    // 反转链表(经典面试题)
    void reverse() {
        Node* prev = nullptr;
        Node* current = head;
        Node* next = nullptr;
        
        while (current) {
            next = current->next;  // 保存下一节点
            current->next = prev;  // 反转指针
            prev = current;        // 前移prev
            current = next;        // 前移current
        }
        head = prev;  // 新头节点
    }

    // 打印链表
    void display() {
        Node* current = head;
        while (current) {
            cout << current->data;
            if (current->next) cout << " -> ";
            current = current->next;
        }
        cout << " -> nullptr" << endl;
    }
};

// 测试用例
int main() {
    LinkedList list;
    
    cout << "插入节点测试:" << endl;
    list.insertAtTail(1);
    list.insertAtTail(2);
    list.insertAtHead(0);
    list.insertAtIndex(2, 99);
    list.display();  // 0 -> 1 -> 99 -> 2 -> nullptr
    
    cout << "\n删除节点测试:" << endl;
    list.deleteByValue(99);
    list.deleteByIndex(0);
    list.display();  // 1 -> 2 -> nullptr
    
    cout << "\n反转链表测试:" << endl;
    list.insertAtHead(3);
    list.reverse();
    list.display();  // 2 -> 1 -> 3 -> nullptr
    
    cout << "\n查找测试:" << endl;
    cout << "Contains 1: " << boolalpha << list.contains(1) << endl;  // true
    cout << "Contains 5: " << boolalpha << list.contains(5) << endl;  // false
    
    return 0;
}

关键操作解析

  1. 头插法

    newNode->next = head;
    head = newNode;
    
  2. 尾插法

    while (current->next) current = current->next;  // 定位尾节点
    current->next = newNode;
    
  3. 反转链表

    // 三指针法:
    while (current) {
        next = current->next;   // 保存下一节点
        current->next = prev;   // 指针转向
        prev = current;         // 前移prev
        current = next;         // 前移current
    }
    head = prev;  // 更新头指针
    
  4. 内存管理

    • 构造函数初始化头指针为 nullptr
    • 析构函数遍历释放所有节点内存
    • 删除节点时注意更新指针关系

应用场景

  1. 需要频繁插入/删除的场景
  2. 实现栈、队列等数据结构
  3. 动态内存分配(操作系统内存管理)
  4. 音乐/视频播放列表
  5. 浏览器历史记录管理

注意:单链表的变体还有双向链表(双指针)和循环链表(尾节点指向头节点),在不同场景下各有优势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九层指针

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值