C++ 单链表教程

单链表是一种常见的线性数据结构,它由一系列节点组成,每个节点包含两个部分:

  • 数据域:存储数据
  • 指针域:指向下一个节点

与数组不同的是,链表在内存中不是连续存储的,而是通过指针将各个节点连接起来。


📌 一、定义节点结构体

我们先用 struct 定义一个链表节点:

#include <iostream>
using namespace std;

// 定义链表节点结构体
struct Node {
    int data;         // 数据域,存储整型数据
    Node* next;       // 指针域,指向下一个节点

    // 构造函数,方便创建节点时初始化数据
    Node(int val) : data(val), next(nullptr) {}
};

✅ 解释:

  • data 是节点存储的数据。
  • next 是一个指向下一个节点的指针。
  • 构造函数 Node(int val) 让我们能更方便地创建节点对象。

📌 二、创建并操作链表

我们将实现以下基本操作:

  1. 在链表末尾插入节点
  2. 打印链表内容
  3. 删除指定值的节点
  4. 清空链表

✅ 2.1 插入节点(尾插法)

// 在链表末尾插入新节点
void insert(Node*& head, int val) {
    Node* newNode = new Node(val);  // 创建新节点

    if (head == nullptr) {          // 如果链表为空
        head = newNode;             // 新节点成为头节点
    } else {
        Node* temp = head;
        while (temp->next != nullptr) {  // 找到最后一个节点
            temp = temp->next;
        }
        temp->next = newNode;       // 将最后一个节点的 next 指向新节点
    }
}

🔁 注意:这里使用了 Node*& head 表示对头指针的引用,可以修改头指针本身。


✅ 2.2 打印链表

// 打印链表内容
void printList(Node* head) {
    Node* temp = head;
    while (temp != nullptr) {
        cout << temp->data << " -> ";
        temp = temp->next;
    }
    cout << "NULL" << endl;
}

✅ 2.3 删除指定值的节点

// 删除第一个等于 val 的节点
void deleteNode(Node*& head, int val) {
    if (head == nullptr) return;  // 链表为空,直接返回

    // 如果头节点就是要删除的节点
    if (head->data == val) {
        Node* toDelete = head;
        head = head->next;        // 更新头节点
        delete toDelete;          // 释放内存
        return;
    }

    // 查找要删除的节点
    Node* temp = head;
    while (temp->next != nullptr && temp->next->data != val) {
        temp = temp->next;
    }

    // 如果找到了目标节点
    if (temp->next != nullptr) {
        Node* toDelete = temp->next;
        temp->next = temp->next->next;  // 跳过该节点
        delete toDelete;                // 释放内存
    } else {
        cout << "未找到值为 " << val << " 的节点。" << endl;
    }
}

✅ 2.4 清空链表

// 清空整个链表
void clearList(Node*& head) {
    while (head != nullptr) {
        Node* toDelete = head;
        head = head->next;
        delete toDelete;
    }
}

📌 三、主函数测试

int main() {
    Node* head = nullptr;  // 初始化头指针为空

    // 插入节点
    insert(head, 10);
    insert(head, 20);
    insert(head, 30);

    // 打印链表
    cout << "原始链表:" << endl;
    printList(head);  // 输出: 10 -> 20 -> 30 -> NULL

    // 删除节点
    deleteNode(head, 20);
    cout << "删除值为20的节点后:" << endl;
    printList(head);  // 输出: 10 -> 30 -> NULL

    // 清空链表
    clearList(head);
    cout << "清空链表后:" << endl;
    printList(head);  // 输出: NULL

    return 0;
}

🧠 总结

操作 时间复杂度
插入(尾插) O(n)
删除
查找
打印

📝 小贴士

  • 使用 new 动态分配内存,记得用 delete 回收内存,避免内存泄漏。
  • 修改头指针时要用 Node*& 引用传递。
  • 单链表适合频繁插入/删除的场景,但访问效率不如数组高。

如果你希望我继续扩展这个教程,比如添加:

  • 头插法
  • 中间插入
  • 反转链表
  • 环形链表判断 请告诉我!我可以为你进一步补充。

1 条评论

  • @ 2025-6-9 21:20:21

    C++单链表教程

    单链表是一种常见的数据结构,由多个节点组成,每个节点包含数据和指向下一个节点的指针。链表的优点是插入和删除操作效率高,但随机访问效率低。

    下面是一个完整的单链表实现示例:

    #include <iostream>
    
    // 定义单链表节点结构体
    struct Node {
        int data;         // 节点存储的数据
        Node* next;       // 指向下一个节点的指针
        
        // 构造函数,方便节点初始化
        Node(int value) : data(value), next(nullptr) {}
    };
    
    // 单链表类,封装链表操作
    class LinkedList {
    private:
        Node* head;       // 头指针,指向链表的第一个节点
        Node* tail;       // 尾指针,指向链表的最后一个节点
        int size;         // 链表的大小
        
    public:
        // 构造函数,初始化空链表
        LinkedList() : head(nullptr), tail(nullptr), size(0) {}
        
        // 析构函数,释放链表占用的内存
        ~LinkedList() {
            clear();
        }
        
        // 判断链表是否为空
        bool isEmpty() const {
            return size == 0;
        }
        
        // 获取链表的大小
        int getSize() const {
            return size;
        }
        
        // 在链表尾部添加元素
        void append(int value) {
            Node* newNode = new Node(value);
            
            if (isEmpty()) {
                // 如果链表为空,新节点既是头节点也是尾节点
                head = tail = newNode;
            } else {
                // 否则将新节点连接到尾部,并更新尾指针
                tail->next = newNode;
                tail = newNode;
            }
            
            size++;
        }
        
        // 在链表头部添加元素
        void prepend(int value) {
            Node* newNode = new Node(value);
            
            if (isEmpty()) {
                // 如果链表为空,新节点既是头节点也是尾节点
                head = tail = newNode;
            } else {
                // 否则将新节点插入到头部,并更新头指针
                newNode->next = head;
                head = newNode;
            }
            
            size++;
        }
        
        // 在指定位置插入元素
        bool insert(int index, int value) {
            if (index < 0 || index > size) {
                std::cout << "插入位置无效" << std::endl;
                return false;
            }
            
            if (index == 0) {
                prepend(value);
                return true;
            }
            
            if (index == size) {
                append(value);
                return true;
            }
            
            // 找到插入位置的前一个节点
            Node* prev = head;
            for (int i = 0; i < index - 1; i++) {
                prev = prev->next;
            }
            
            // 创建新节点并插入到链表中
            Node* newNode = new Node(value);
            newNode->next = prev->next;
            prev->next = newNode;
            
            size++;
            return true;
        }
        
        // 删除指定位置的元素
        bool remove(int index) {
            if (index < 0 || index >= size) {
                std::cout << "删除位置无效" << std::endl;
                return false;
            }
            
            Node* toDelete;
            
            if (index == 0) {
                // 删除头节点
                toDelete = head;
                head = head->next;
                
                if (head == nullptr) {
                    // 如果链表只有一个节点,删除后尾指针也要置空
                    tail = nullptr;
                }
            } else {
                // 找到删除位置的前一个节点
                Node* prev = head;
                for (int i = 0; i < index - 1; i++) {
                    prev = prev->next;
                }
                
                toDelete = prev->next;
                prev->next = toDelete->next;
                
                if (toDelete == tail) {
                    // 如果删除的是尾节点,更新尾指针
                    tail = prev;
                }
            }
            
            // 释放删除节点的内存
            delete toDelete;
            size--;
            return true;
        }
        
        // 查找元素在链表中的位置
        int find(int value) const {
            Node* current = head;
            int index = 0;
            
            while (current != nullptr) {
                if (current->data == value) {
                    return index;
                }
                current = current->next;
                index++;
            }
            
            return -1;  // 未找到元素
        }
        
        // 打印链表中的所有元素
        void print() const {
            Node* current = head;
            
            while (current != nullptr) {
                std::cout << current->data << " ";
                current = current->next;
            }
            
            std::cout << std::endl;
        }
        
        // 清空链表
        void clear() {
            Node* current = head;
            
            while (current != nullptr) {
                Node* nextNode = current->next;
                delete current;
                current = nextNode;
            }
            
            head = tail = nullptr;
            size = 0;
        }
    };
    
    // 使用示例
    int main() {
        LinkedList list;
        
        // 在尾部添加元素
        list.append(10);
        list.append(20);
        list.append(30);
        
        std::cout << "链表内容: ";
        list.print();  // 输出: 10 20 30
        
        // 在头部添加元素
        list.prepend(5);
        
        std::cout << "在头部添加5后: ";
        list.print();  // 输出: 5 10 20 30
        
        // 在指定位置插入元素
        list.insert(2, 15);
        
        std::cout << "在位置2插入15后: ";
        list.print();  // 输出: 5 10 15 20 30
        
        // 删除指定位置的元素
        list.remove(3);
        
        std::cout << "删除位置3的元素后: ";
        list.print();  // 输出: 5 10 15 30
        
        // 查找元素
        int pos = list.find(15);
        std::cout << "元素15的位置是: " << pos << std::endl;  // 输出: 2
        
        // 清空链表
        list.clear();
        std::cout << "清空链表后,链表大小: " << list.getSize() << std::endl;  // 输出: 0
        
        return 0;
    }
    

    代码解释

    1. Node结构体

      • 包含一个整数data存储节点数据
      • 包含一个指向下一个节点的指针next
      • 构造函数用于初始化节点数据
    2. LinkedList类

      • headtail指针分别指向链表的头部和尾部
      • size记录链表的大小
      • 提供了链表的基本操作方法,如添加、删除、查找等
    3. 主要方法说明

      • append(): 在链表尾部添加元素
      • prepend(): 在链表头部添加元素
      • insert(): 在指定位置插入元素
      • remove(): 删除指定位置的元素
      • find(): 查找元素位置
      • print(): 打印链表内容
      • clear(): 清空链表

    单链表的核心在于节点之间通过指针连接,插入和删除操作只需要修改指针指向,无需移动大量数据,因此效率较高。但访问元素需要从头节点开始遍历,时间复杂度为O(n)。

    • 1