作业介绍

一、教学目标:

1、 理解链表 “离散存储、通过指针连接” 的核心特性,区分链表与数组的存储差异;掌握单链表的基本概念(节点、头指针、尾指针)及核心操作(增、删、查、改)的定义。

2、 能基于 C++ 结构体 / 类实现单链表的节点定义,完成单链表的初始化、头插 / 尾插法添加节点、按值 / 按索引查找节点、删除指定节点等基础操作的代码编写;能手动模拟单链表操作的指针指向变化,处理空链表、删除头 / 尾节点等边界场景。

3、 能识别链表的基础适用场景(如频繁增删、数据量不固定),使用自定义单链表解决简单问题(如逆序输出链表元素、统计链表长度)。

二、 核心知识点

1. 链表基本概念

链表定义与特点

  • 定义:由一系列节点组成的数据结构,每个节点包含数据和指向下一个节点的指针
  • 特点
    • 动态大小,无需预先分配空间
    • 内存不连续,通过指针链接
    • 插入删除高效(O(1)),随机访问低效(O(n))

链表分类

1. 单向链表(Singly Linked List)
2. 双向链表(Doubly Linked List)
3. 循环链表(Circular Linked List)
4. 双向循环链表(Doubly Circular Linked List)

2. 节点结构定义

单向链表节点

struct ListNode {
    int val;          // 数据域
    ListNode* next;   // 指针域,指向下一个节点
    
    // 构造函数
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode* nxt) : val(x), next(nxt) {}
};

双向链表节点

struct DoublyListNode {
    int val;
    DoublyListNode* prev;  // 指向前一个节点
    DoublyListNode* next;  // 指向下一个节点
    
    // 构造函数
    DoublyListNode(int x) : val(x), prev(nullptr), next(nullptr) {}
};

3. 基本操作实现

单向链表完整实现

class SinglyLinkedList {
private:
    ListNode* head;
    int size;
    
public:
    // 构造函数
    SinglyLinkedList() : head(nullptr), size(0) {}
    
    // 析构函数(重要!释放内存)
    ~SinglyLinkedList() {
        while (head) {
            ListNode* temp = head;
            head = head->next;
            delete temp;
        }
    }
    
    // 1. 获取链表大小
    int getSize() const {
        return size;
    }
    
    // 2. 判断是否为空
    bool isEmpty() const {
        return head == nullptr;
    }
    
    // 3. 头部插入
    void insertAtHead(int val) {
        ListNode* newNode = new ListNode(val);
        newNode->next = head;
        head = newNode;
        size++;
    }
    
    // 4. 尾部插入
    void insertAtTail(int val) {
        ListNode* newNode = new ListNode(val);
        
        if (!head) {
            head = newNode;
        } else {
            ListNode* current = head;
            while (current->next) {
                current = current->next;
            }
            current->next = newNode;
        }
        size++;
    }
    
    // 5. 指定位置插入
    void insertAtIndex(int index, int val) {
        if (index < 0 || index > size) {
            throw out_of_range("Index out of range");
        }
        
        if (index == 0) {
            insertAtHead(val);
            return;
        }
        
        ListNode* newNode = new ListNode(val);
        ListNode* current = head;
        
        // 移动到插入位置的前一个节点
        for (int i = 0; i < index - 1; i++) {
            current = current->next;
        }
        
        newNode->next = current->next;
        current->next = newNode;
        size++;
    }
    
    // 6. 删除头部
    void deleteAtHead() {
        if (!head) return;
        
        ListNode* temp = head;
        head = head->next;
        delete temp;
        size--;
    }
    
    // 7. 删除尾部
    void deleteAtTail() {
        if (!head) return;
        
        if (!head->next) {
            delete head;
            head = nullptr;
            size--;
            return;
        }
        
        ListNode* current = head;
        while (current->next && current->next->next) {
            current = current->next;
        }
        
        delete current->next;
        current->next = nullptr;
        size--;
    }
    
    // 8. 删除指定值
    void deleteByValue(int val) {
        if (!head) return;
        
        // 处理头节点就是要删除的情况
        while (head && head->val == val) {
            ListNode* temp = head;
            head = head->next;
            delete temp;
            size--;
        }
        
        if (!head) return;
        
        ListNode* current = head;
        while (current->next) {
            if (current->next->val == val) {
                ListNode* temp = current->next;
                current->next = current->next->next;
                delete temp;
                size--;
            } else {
                current = current->next;
            }
        }
    }
    
    // 9. 查找元素
    bool contains(int val) const {
        ListNode* current = head;
        while (current) {
            if (current->val == val) {
                return true;
            }
            current = current->next;
        }
        return false;
    }
    
    // 10. 获取指定位置的元素
    int get(int index) const {
        if (index < 0 || index >= size) {
            throw out_of_range("Index out of range");
        }
        
        ListNode* current = head;
        for (int i = 0; i < index; i++) {
            current = current->next;
        }
        return current->val;
    }
    
    // 11. 修改指定位置的元素
    void set(int index, int val) {
        if (index < 0 || index >= size) {
            throw out_of_range("Index out of range");
        }
        
        ListNode* current = head;
        for (int i = 0; i < index; i++) {
            current = current->next;
        }
        current->val = val;
    }
    
    // 12. 打印链表
    void print() const {
        ListNode* current = head;
        cout << "List: ";
        while (current) {
            cout << current->val;
            if (current->next) {
                cout << " -> ";
            }
            current = current->next;
        }
        cout << " -> NULL" << endl;
        cout << "Size: " << size << endl;
    }
    
    // 13. 反转链表
    void reverse() {
        ListNode* prev = nullptr;
        ListNode* current = head;
        ListNode* next = nullptr;
        
        while (current) {
            next = current->next;  // 保存下一个节点
            current->next = prev;  // 反转指针
            prev = current;        // 移动prev
            current = next;        // 移动current
        }
        
        head = prev;
    }
};

双向链表实现(关键部分)

class DoublyLinkedList {
private:
    DoublyListNode* head;
    DoublyListNode* tail;
    int size;
    
public:
    DoublyLinkedList() : head(nullptr), tail(nullptr), size(0) {}
    
    ~DoublyLinkedList() {
        while (head) {
            DoublyListNode* temp = head;
            head = head->next;
            delete temp;
        }
    }
    
    // 尾部插入(双向链表的优势)
    void insertAtTail(int val) {
        DoublyListNode* newNode = new DoublyListNode(val);
        
        if (!tail) {
            // 链表为空
            head = tail = newNode;
        } else {
            tail->next = newNode;
            newNode->prev = tail;
            tail = newNode;
        }
        size++;
    }
    
    // 头部插入
    void insertAtHead(int val) {
        DoublyListNode* newNode = new DoublyListNode(val);
        
        if (!head) {
            head = tail = newNode;
        } else {
            newNode->next = head;
            head->prev = newNode;
            head = newNode;
        }
        size++;
    }
    
    // 删除尾部(O(1)复杂度)
    void deleteAtTail() {
        if (!tail) return;
        
        if (head == tail) {
            delete head;
            head = tail = nullptr;
        } else {
            DoublyListNode* temp = tail;
            tail = tail->prev;
            tail->next = nullptr;
            delete temp;
        }
        size--;
    }
};

4. C++ STL 链表使用

std::list(双向链表)

#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

void demonstrateList() {
    // 1. 创建和初始化
    list<int> myList = {1, 2, 3, 4, 5};
    list<int> emptyList;
    list<int> sizedList(10);        // 10个0
    list<int> filledList(5, 42);    // 5个42
    
    // 2. 插入元素
    myList.push_front(0);           // 头部插入
    myList.push_back(6);            // 尾部插入
    
    auto it = myList.begin();
    advance(it, 3);                 // 移动迭代器
    myList.insert(it, 99);          // 指定位置插入
    
    // 3. 删除元素
    myList.pop_front();             // 删除头部
    myList.pop_back();              // 删除尾部
    myList.remove(3);               // 删除所有值为3的元素
    
    // 4. 遍历
    cout << "Forward: ";
    for (int val : myList) {
        cout << val << " ";
    }
    cout << endl;
    
    cout << "Backward: ";
    for (auto rit = myList.rbegin(); rit != myList.rend(); ++rit) {
        cout << *rit << " ";
    }
    cout << endl;
    
    // 5. 其他操作
    myList.sort();                  // 排序
    myList.reverse();               // 反转
    myList.unique();                // 删除连续重复元素
    myList.resize(10);              // 调整大小
}

std::forward_list(单向链表)

#include <forward_list>

void demonstrateForwardList() {
    // forward_list 只支持前向遍历
    forward_list<int> flist = {1, 2, 3, 4, 5};
    
    // 插入(使用 insert_after)
    auto it = flist.begin();
    flist.insert_after(it, 99);     // 在第一个元素后插入
    
    // 删除(使用 erase_after)
    it = flist.begin();
    flist.erase_after(it);          // 删除第二个元素
    
    // 遍历(只有前向迭代器)
    for (int val : flist) {
        cout << val << " ";
    }
}

题目

认领作业后才可以查看作业内容。
状态
正在进行…
题目
8
开始时间
2026-3-13 0:00
截止时间
2036-3-20 23:59
可延期
24 小时