C++数据结构——链表

链表基础与核心概念

链表是一种动态数据结构,它通过指针将一组零散的内存块串联起来使用。与数组相比,链表在插入和删除操作上更加高效,但失去了随机访问的能力。

为什么使用链表?

1.动态大小:不需要预先知道数据量大小
2.高效插入/删除:O(1)时间复杂度(已知位置时)
3.内存效率:不需要连续内存空间

一、链表核心组件详解

1. ListNode 结构体深度解析

struct ListNode {
    int val;        // 数据域 - 存储节点值
    ListNode* next; // 指针域 - 指向下一个节点
    
    // 构造函数家族
    ListNode() : val(0), next(nullptr) {
        // 默认构造函数,创建空节点
    }
    
    ListNode(int x) : val(x), next(nullptr) {
        // 带值构造函数,next自动初始化为nullptr
        // 确保新节点不会意外指向其他内存
    }
    
    ListNode(int x, ListNode* next) : val(x), next(next) {
        // 完整构造函数,允许指定下一个节点
        // 常用于构建特定结构的链表
    }
    
    // 析构函数(高级用法)
    ~ListNode() {
        // 注意:通常不在节点析构函数中处理next指针
        // 因为链表管理应由链表类负责
        // 但如果节点包含需要清理的资源,可以在此处理
    }
    
    // 成员函数示例(高级用法)
    void setNext(ListNode* node) {
        next = node;
    }
    
    ListNode* getNext() const {
        return next;
    }
    
    int getValue() const {
        return val;
    }
    
    void setValue(int value) {
        val = value;
    }
};

关键点说明

  • next指针必须正确初始化,否则会成为野指针
  • 构造函数重载提供了多种创建节点的方式
  • 析构函数通常保持简单,复杂清理应由链表类处理
  • 添加成员函数可以封装节点操作,提高安全性

2. LinkedList 类完整实现

class LinkedList {
private:
    ListNode* head; // 头节点指针
    ListNode* tail; // 尾节点指针(优化尾部操作)
    size_t size;    // 链表长度(使用size_t避免负数)
    
    // 私有工具函数
    ListNode* getNodeAt(int index) const {
        if (index < 0 || index >= size) return nullptr;
        
        ListNode* current = head;
        for (int i = 0; i < index; ++i) {
            current = current->next;
        }
        return current;
    }
    
public:
    // 构造函数家族
    LinkedList() : head(nullptr), tail(nullptr), size(0) {
        // 默认构造空链表
    }
    
    LinkedList(std::initializer_list<int> initList) : LinkedList() {
        // 初始化列表构造
        for (int val : initList) {
            append(val);
        }
    }
    
    // 拷贝构造函数(深拷贝)
    LinkedList(const LinkedList& other) : LinkedList() {
        ListNode* current = other.head;
        while (current != nullptr) {
            append(current->val);
            current = current->next;
        }
    }
    
    // 移动构造函数(C++11)
    LinkedList(LinkedList&& other) noexcept 
        : head(other.head), tail(other.tail), size(other.size) {
        other.head = other.tail = nullptr;
        other.size = 0;
    }
    
    // 析构函数
    ~LinkedList() {
        clear(); // 确保释放所有节点
    }
    
    // 赋值运算符重载
    LinkedList& operator=(const LinkedList& other) {
        if (this != &other) {
            clear();
            ListNode* current = other.head;
            while (current != nullptr) {
                append(current->val);
                current = current->next;
            }
        }
        return *this;
    }
    
    // 移动赋值运算符(C++11)
    LinkedList& operator=(LinkedList&& other) noexcept {
        if (this != &other) {
            clear();
            head = other.head;
            tail = other.tail;
            size = other.size;
            other.head = other.tail = nullptr;
            other.size = 0;
        }
        return *this;
    }
    
    // 容量操作
    bool isEmpty() const { return size == 0; }
    size_t getSize() const { return size; }
    
    // 元素访问(带边界检查)
    int& operator[](int index) {
        ListNode* node = getNodeAt(index);
        if (node == nullptr) {
            throw std::out_of_range("Index out of bounds");
        }
        return node->val;
    }
    
    const int& operator[](int index) const {
        return const_cast<LinkedList*>(this)->operator[](index);
    }
    
    int front() const {
        if (isEmpty()) throw std::out_of_range("List is empty");
        return head->val;
    }
    
    int back() const {
        if (isEmpty()) throw std::out_of_range("List is empty");
        return tail->val;
    }
    
    // 修改操作
    void append(int value) {
        ListNode* newNode = new ListNode(value);
        
        if (isEmpty()) {
            head = tail = newNode;
        } else {
            tail->next = newNode;
            tail = newNode;
        }
        ++size;
    }
    
    void prepend(int value) {
        ListNode* newNode = new ListNode(value, head);
        head = newNode;
        if (tail == nullptr) {
            tail = head;
        }
        ++size;
    }
    
    bool insert(int index, int value) {
        if (index < 0 || index > size) return false;
        
        if (index == 0) {
            prepend(value);
        } else if (index == size) {
            append(value);
        } else {
            ListNode* prev = getNodeAt(index - 1);
            ListNode* newNode = new ListNode(value, prev->next);
            prev->next = newNode;
            ++size;
        }
        return true;
    }
    
    bool removeAt(int index) {
        if (index < 0 || index >= size) return false;
        
        ListNode* toDelete = nullptr;
        
        if (index == 0) {
            toDelete = head;
            head = head->next;
            if (head == nullptr) {
                tail = nullptr;
            }
        } else {
            ListNode* prev = getNodeAt(index - 1);
            toDelete = prev->next;
            prev->next = toDelete->next;
            
            if (toDelete == tail) {
                tail = prev;
            }
        }
        
        delete toDelete;
        --size;
        return true;
    }
    
    void clear() {
        while (head != nullptr) {
            ListNode* temp = head;
            head = head->next;
            delete temp;
        }
        tail = nullptr;
        size = 0;
    }
    
    // 高级操作
    void reverse() {
        ListNode *prev = nullptr, *current = head, *next = nullptr;
        tail = head; // 反转后尾节点变为原头节点
        
        while (current != nullptr) {
            next = current->next; // 保存下一个节点
            current->next = prev; // 反转当前节点的指针
            prev = current;       // 移动prev指针
            current = next;       // 移动current指针
        }
        
        head = prev; // 最后prev指向新的头节点
    }
    
    // 迭代器支持(简化版)
    class Iterator {
        ListNode* current;
    public:
        Iterator(ListNode* node) : current(node) {}
        
        int& operator*() { return current->val; }
        Iterator& operator++() { 
            current = current->next; 
            return *this;
        }
        bool operator!=(const Iterator& other) const {
            return current != other.current;
        }
    };
    
    Iterator begin() { return Iterator(head); }
    Iterator end() { return Iterator(nullptr); }
    
    // 输出链表
    friend std::ostream& operator<<(std::ostream& os, const LinkedList& list) {
        ListNode* current = list.head;
        os << "[";
        while (current != nullptr) {
            os << current->val;
            if (current->next != nullptr) {
                os << " -> ";
            }
            current = current->next;
        }
        os << "]";
        return os;
    }
};

二、高级特性深度解析

1. 迭代器实现详解

// 完整迭代器实现
class Iterator {
    ListNode* current;
public:
    using iterator_category = std::forward_iterator_tag;
    using value_type = int;
    using difference_type = std::ptrdiff_t;
    using pointer = int*;
    using reference = int&;
    
    explicit Iterator(ListNode* node = nullptr) : current(node) {}
    
    // 解引用运算符
    reference operator*() const {
        if (current == nullptr) {
            throw std::runtime_error("Dereferencing null iterator");
        }
        return current->val;
    }
    
    // 成员访问运算符
    pointer operator->() const {
        return &(operator*());
    }
    
    // 前缀++
    Iterator& operator++() {
        if (current != nullptr) {
            current = current->next;
        }
        return *this;
    }
    
    // 后缀++
    Iterator operator++(int) {
        Iterator temp = *this;
        ++(*this);
        return temp;
    }
    
    // 相等比较
    bool operator==(const Iterator& other) const {
        return current == other.current;
    }
    
    bool operator!=(const Iterator& other) const {
        return !(*this == other);
    }
    
    // 转换为bool(判断是否有效)
    explicit operator bool() const {
        return current != nullptr;
    }
    
    // 获取内部指针(高级用法)
    ListNode* node() const {
        return current;
    }
};

使用示例

LinkedList list = {1, 2, 3, 4, 5};

// 使用迭代器遍历
for (LinkedList::Iterator it = list.begin(); it != list.end(); ++it) {
    std::cout << *it << " ";
}

// 使用范围for循环(C++11)
for (int val : list) {
    std::cout << val << " ";
}

// 使用STL算法
auto it = std::find(list.begin(), list.end(), 3);
if (it != list.end()) {
    std::cout << "Found: " << *it;
}

2. 异常安全实现

// 异常安全的插入操作
bool insertSafe(int index, int value) {
    // 先创建新节点(可能抛出bad_alloc)
    ListNode* newNode = nullptr;
    try {
        newNode = new ListNode(value);
    } catch (const std::bad_alloc&) {
        return false; // 内存分配失败
    }
    
    // 空链表情况
    if (isEmpty()) {
        if (index != 0) {
            delete newNode;
            return false;
        }
        head = tail = newNode;
        ++size;
        return true;
    }
    
    // 插入头部
    if (index == 0) {
        newNode->next = head;
        head = newNode;
        ++size;
        return true;
    }
    
    // 插入中间或尾部
    try {
        ListNode* prev = getNodeAt(index - 1);
        if (prev == nullptr && index != size) {
            delete newNode;
            return false;
        }
        
        newNode->next = prev->next;
        prev->next = newNode;
        
        if (prev == tail) {
            tail = newNode;
        }
        
        ++size;
        return true;
    } catch (...) {
        delete newNode;
        throw; // 重新抛出异常
    }
}

3. 线程安全扩展(C++11)

#include <mutex>

class ThreadSafeLinkedList {
private:
    LinkedList list;
    mutable std::mutex mtx;
    
public:
    void append(int value) {
        std::lock_guard<std::mutex> lock(mtx);
        list.append(value);
    }
    
    bool insert(int index, int value) {
        std::lock_guard<std::mutex> lock(mtx);
        return list.insert(index, value);
    }
    
    // 其他方法的线程安全包装...
    
    // 提供原子快照
    LinkedList snapshot() const {
        std::lock_guard<std::mutex> lock(mtx);
        return list; // 调用拷贝构造函数
    }
};

三、性能优化技巧

1. 内存池优化

class ListNodePool {
private:
    std::vector<ListNode*> pool;
    size_t chunkSize = 100;
    
    void allocateChunk() {
        pool.reserve(pool.size() + chunkSize);
        for (size_t i = 0; i < chunkSize; ++i) {
            pool.push_back(new ListNode(0));
        }
    }
    
public:
    ListNode* acquire(int value) {
        if (pool.empty()) {
            allocateChunk();
        }
        
        ListNode* node = pool.back();
        pool.pop_back();
        node->val = value;
        node->next = nullptr;
        return node;
    }
    
    void release(ListNode* node) {
        if (node != nullptr) {
            node->next = nullptr;
            pool.push_back(node);
        }
    }
    
    ~ListNodePool() {
        for (ListNode* node : pool) {
            delete node;
        }
    }
};

// 使用内存池的链表
class OptimizedLinkedList {
private:
    ListNodePool pool;
    // ... 其他成员
public:
    void append(int value) {
        ListNode* newNode = pool.acquire(value);
        // ... 其他操作
    }
    
    void removeAt(int index) {
        // ... 找到要删除的节点
        pool.release(toDelete);
    }
};

2. 缓存优化

class CachedLinkedList {
private:
    ListNode* head;
    ListNode* tail;
    size_t size;
    
    // 缓存最近访问的节点
    mutable struct {
        ListNode* node = nullptr;
        int index = -1;
    } cache;
    
    ListNode* getNodeAt(int index) const {
        if (index < 0 || index >= size) return nullptr;
        
        // 检查缓存
        if (cache.index != -1 && std::abs(cache.index - index) < 3) {
            if (cache.index == index) return cache.node;
            
            ListNode* current = cache.node;
            int step = index > cache.index ? 1 : -1;
            
            while (current != nullptr && cache.index != index) {
                current = (step > 0) ? current->next : /* 需要双向链表支持 */;
                cache.index += step;
            }
            
            if (current != nullptr) {
                cache.node = current;
                return current;
            }
        }
        
        // 常规查找
        ListNode* current = head;
        for (int i = 0; i < index; ++i) {
            current = current->next;
        }
        
        // 更新缓存
        cache.node = current;
        cache.index = index;
        
        return current;
    }
    
public:
    // ... 其他方法需要清除缓存
    void clear() {
        // ... 原有清理
        cache.node = nullptr;
        cache.index = -1;
    }
};

四、实际应用案例

1. LRU缓存实现

class LRUCache {
private:
    struct CacheNode {
        int key;
        int value;
        CacheNode* prev;
        CacheNode* next;
        CacheNode(int k, int v) : key(k), value(v), prev(nullptr), next(nullptr) {}
    };
    
    std::unordered_map<int, CacheNode*> cacheMap;
    CacheNode* head; // 最近使用的伪头节点
    CacheNode* tail; // 最久未使用的伪尾节点
    int capacity;
    
    void addToHead(CacheNode* node) {
        node->prev = head;
        node->next = head->next;
        head->next->prev = node;
        head->next = node;
    }
    
    void removeNode(CacheNode* node) {
        node->prev->next = node->next;
        node->next->prev = node->prev;
    }
    
    void moveToHead(CacheNode* node) {
        removeNode(node);
        addToHead(node);
    }
    
    CacheNode* removeTail() {
        CacheNode* node = tail->prev;
        removeNode(node);
        return node;
    }
    
public:
    LRUCache(int capacity) : capacity(capacity) {
        head = new CacheNode(-1, -1);
        tail = new CacheNode(-1, -1);
        head->next = tail;
        tail->prev = head;
    }
    
    int get(int key) {
        if (!cacheMap.count(key)) return -1;
        
        CacheNode* node = cacheMap[key];
        moveToHead(node);
        return node->value;
    }
    
    void put(int key, int value) {
        if (cacheMap.count(key)) {
            CacheNode* node = cacheMap[key];
            node->value = value;
            moveToHead(node);
        } else {
            if (cacheMap.size() == capacity) {
                CacheNode* removed = removeTail();
                cacheMap.erase(removed->key);
                delete removed;
            }
            
            CacheNode* newNode = new CacheNode(key, value);
            cacheMap[key] = newNode;
            addToHead(newNode);
        }
    }
    
    ~LRUCache() {
        for (auto& pair : cacheMap) {
            delete pair.second;
        }
        delete head;
        delete tail;
    }
};

2. 多项式运算实现

class Polynomial {
private:
    struct Term {
        double coefficient;
        int exponent;
        Term* next;
        Term(double coeff, int exp, Term* n = nullptr)
            : coefficient(coeff), exponent(exp), next(n) {}
    };
    
    Term* head;
    
public:
    Polynomial() : head(nullptr) {}
    
    void addTerm(double coeff, int exp) {
        if (coeff == 0.0) return;
        
        if (head == nullptr || exp > head->exponent) {
            head = new Term(coeff, exp, head);
            return;
        }
        
        Term* current = head;
        while (current->next != nullptr && current->next->exponent > exp) {
            current = current->next;
        }
        
        if (current->exponent == exp) {
            current->coefficient += coeff;
            if (current->coefficient == 0.0) {
                // 需要删除该节点
                Term* toDelete = current;
                if (current == head) {
                    head = head->next;
                } else {
                    // 需要找到前驱节点
                    Term* prev = head;
                    while (prev->next != current) {
                        prev = prev->next;
                    }
                    prev->next = current->next;
                }
                delete toDelete;
            }
        } else {
            current->next = new Term(coeff, exp, current->next);
        }
    }
    
    Polynomial add(const Polynomial& other) const {
        Polynomial result;
        Term* p1 = head;
        Term* p2 = other.head;
        
        while (p1 != nullptr && p2 != nullptr) {
            if (p1->exponent > p2->exponent) {
                result.addTerm(p1->coefficient, p1->exponent);
                p1 = p1->next;
            } else if (p1->exponent < p2->exponent) {
                result.addTerm(p2->coefficient, p2->exponent);
                p2 = p2->next;
            } else {
                double sum = p1->coefficient + p2->coefficient;
                if (sum != 0.0) {
                    result.addTerm(sum, p1->exponent);
                }
                p1 = p1->next;
                p2 = p2->next;
            }
        }
        
        // 处理剩余项
        while (p1 != nullptr) {
            result.addTerm(p1->coefficient, p1->exponent);
            p1 = p1->next;
        }
        
        while (p2 != nullptr) {
            result.addTerm(p2->coefficient, p2->exponent);
            p2 = p2->next;
        }
        
        return result;
    }
    
    // ... 其他多项式运算
};

六、性能分析与优化

时间复杂度分析

操作时间复杂度说明
访问O(n)需要遍历
搜索O(n)需要遍历
插入O(1)已知位置时
删除O(1)已知位置时
头部操作O(1)直接操作头指针
尾部操作O(1)有尾指针时
中间操作O(n)需要先找到位置

优化建议

1.维护尾指针:可以显著提高尾部操作效率
2.双向链表:对于需要频繁前向/后向遍历的场景
3.循环链表:适合环形缓冲区等应用场景
4.跳表:对于需要快速查找的有序链表

链表作为基础数据结构,其实现质量直接影响程序性能和稳定性。通过深入理解指针操作、内存管理和各种优化技巧,可以构建出高效可靠的链表实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值