STL详解 - list的模拟实现

目录

1. list 的基本结构

1.1 构造函数

2. 迭代器的实现

2.1 构造函数

2.2 自增和自减操作符

2.3 比较操作符

2.4 解引用和箭头操作符

3. list 容器的实现

3.1 构造函数

3.2 拷贝构造

3.3 赋值运算符重载

3.4 析构函数

3.5 迭代器相关函数

3.6 插入和删除函数

3.7 其他函数

4. 测试代码

5. 源码 


1. list 的基本结构

list 是一个双向链表,每个节点包含两个指针,分别指向其前驱节点和后继节点。我们首先定义一个 ListNode 结构来表示链表中的节点。

STL详解 - list的模拟实现_第1张图片

template
struct ListNode
{
    ListNode* _next;   // 指向后继节点
    ListNode* _prev;   // 指向前驱节点
    T _data;              // 节点存储的数据

    // 构造函数
    ListNode(const T& x = T())
        :_next(nullptr)
        ,_prev(nullptr)
        ,_data(x)
    {}
};

1.1 构造函数

构造函数用于初始化节点。如果未传入数据,则使用默认构造函数初始化数据域。前驱和后继指针初始化为 nullptr

ListNode(const T& x = T())
    :_next(nullptr)
    ,_prev(nullptr)
    ,_data(x)
{}

2. 迭代器的实现

为了方便遍历链表,我们需要定义一个迭代器结构。迭代器需要支持基本的操作,如解引用、自增、自减等。

template
struct ListIterator
{
    typedef ListNode Node;
    typedef ListIterator Self;

    Node* _node;  // 当前节点指针

    // 构造函数
    ListIterator(Node* node)
        :_node(node)
    {}

    // 解引用操作符
    Ref operator*()
    {
        return _node->_data;
    }

    // 箭头操作符
    Ptr operator->()
    {
        return &_node->_data;
    }

    // 前置自增
    Self& operator++()
    {
        _node = _node->_next;
        return *this;
    }

    // 后置自增
    Self operator++(int)
    {
        Self tmp(*this);
        _node = _node->_next;
        return tmp;
    }

    // 前置自减
    Self& operator--()
    {
        _node = _node->_prev;
        return *this;
    }

    // 后置自减
    Self operator--(int)
    {
        Self tmp(*this);
        _node = _node->_prev;
        return tmp;
    }

    // 比较操作符
    bool operator!=(const Self& it)
    {
        return _node != it._node;
    }

    bool operator==(const Self& it)
    {
        return _node == it._node;
    }
};

2.1 构造函数

迭代器的构造函数接收一个节点指针,并将其存储在 _node 中。

ListIterator(Node* node)
    :_node(node)
{}

2.2 自增和自减操作符

自增和自减操作符分别用于移动迭代器到下一个或前一个节点。

Self& operator++()
{
    _node = _node->_next;
    return *this;
}

Self operator++(int)
{
    Self tmp(*this);
    _node = _node->_next;
    return tmp;
}

Self& operator--()
{
    _node = _node->_prev;
    return *this;
}

Self operator--(int)
{
    Self tmp(*this);
    _node = _node->_prev;
    return tmp;
}

2.3 比较操作符

比较操作符用于判断两个迭代器是否指向同一个节点。

bool operator!=(const Self& it)
{
    return _node != it._node;
}

bool operator==(const Self& it)
{
    return _node == it._node;
}

2.4 解引用和箭头操作符

解引用和箭头操作符用于访问节点中的数据。

Ref operator*()
{
    return _node->_data;
}

Ptr operator->()
{
    return &_node->_data;
}

3. list 容器的实现

list 容器需要管理链表的头节点,并提供插入、删除、遍历等操作。

template
class list
{
public:
    typedef ListNode Node;
    typedef ListIterator iterator;
    typedef ListIterator const_iterator;

    // 迭代器相关函数
    iterator begin()
    {
        return _head->_next;
    }

    iterator end()
    {
        return _head;
    }

    const_iterator begin() const
    {
        return _head->_next;
    }

    const_iterator end() const
    {
        return _head;
    }

    // 构造函数
    list()
    {
        empty_init();
    }

    // 拷贝构造
    list(const list& lt)
    {
        empty_init();
        for (auto& e : lt)
        {
            push_back(e);
        }
    }

    // 赋值运算符重载
    list& operator=(list& lt)
    {
        swap(lt);
        return *this;
    }

    // 析构函数
    ~list()
    {
        clear();
        delete _head;
        _head = nullptr;
    }

    // 插入、删除函数
    void insert(iterator pos, const T& val)
    {
        Node* cur = pos._node;
        Node* newnode = new Node(val);
        Node* prev = cur->_prev;

        prev->_next = newnode;
        newnode->_prev = prev;
        newnode->_next = cur;
        cur->_prev = newnode;
        _size++;
    }

    iterator erase(iterator pos)
    {
        Node* cur = pos._node;
        Node* next = cur->_next;
        Node* prev = cur->_prev;

        prev->_next = next;
        next->_prev = prev;
        delete cur;
        _size--;

        return iterator(next);
    }

    void push_back(const T& x)
    {
        insert(end(), x);
    }

    void push_front(const T& x)
    {
        insert(begin(), x);
    }

    void pop_back()
    {
        erase(--end());
    }

    void pop_front()
    {
        erase(begin());
    }

    // 其他函数
    size_t size() const
    {
        return _size;
    }

    bool empty()
    {
        return _size == 0;
    }

    void clear()
    {
        iterator it = begin();
        while (it != end())
        {
            it = erase(it);
        }
    }

    void swap(list& lt)
    {
        std::swap(_head, lt._head);
        std::swap(_size, lt._size);
    }

private:
    Node* _head;  // 指向链表头结点的指针
    size_t _size; // 链表大小

    // 初始化空链表
    void empty_init()
    {
        _head = new Node;
        _head->_next = _head;
        _head->_prev = _head;
        _size = 0;
    }
};

3.1 构造函数

  • 初始化一个空链表,确保链表的头节点 _head 被正确创建。

  • 头节点的前驱和后继指针都指向自身,形成一个循环链表。

  • 初始化 _size 为 0,表示链表为空。

// 初始化空链表
void empty_init()
{
	_head = new Node;
	_head->_next = _head;
	_head->_prev = _head;
	_size = 0;
}
list()
{
    empty_init();
}

3.2 拷贝构造

  • 首先调用 empty_init() 初始化一个空链表。

  • 遍历源列表 lt,将每个元素通过 push_back 插入到新列表中。

  • 这种方式确保新列表与源列表具有相同的元素顺序。

list(const list& lt)
{
    empty_init();
    for (auto& e : lt)
    {
        push_back(e);
    }
}

3.3 赋值运算符重载

赋值运算符重载函数通过交换两个列表的头节点来实现高效赋值。

  • 通过交换两个列表的头节点 _head 和大小 _size,可以高效地完成赋值操作。

  • 这种方式避免了逐个元素的复制,提高了效率。

  • 调用 swap 函数后,原列表的内容被交换到当前列表中。

list& operator=(list& lt)
{
    swap(lt);
    return *this;
}

3.4 析构函数

  • 首先调用 clear() 清空列表,释放所有节点。

  • 删除头节点 _head,并将其置为 nullptr,避免悬空指针。

~list()
{
    clear();
    delete _head;
    _head = nullptr;
}

3.5 迭代器相关函数

  • begin() 返回头节点的下一个节点,即第一个有效节点。

  • end() 返回头节点本身,表示迭代的结束位置。

iterator begin()
{
    return _head->_next;
}

iterator end()
{
    return _head;
}

3.6 插入和删除函数

insert 函数在指定位置插入一个新节点。

  • 获取当前节点 cur 和其前驱节点 prev

  • 创建一个新节点 newnode,并初始化其数据和指针。

  • 调整 prev cur 的指针,将新节点插入到链表中。

  • 更新链表大小 _size

void insert(iterator pos, const T& val)
{
    Node* cur = pos._node;
    Node* newnode = new Node(val);
    Node* prev = cur->_prev;

    prev->_next = newnode;
    newnode->_prev = prev;
    newnode->_next = cur;
    cur->_prev = newnode;
    _size++;
}

erase 函数删除指定位置的节点。

  • 获取当前节点 cur、其前驱节点 prev 和后继节点 next

  • 调整 prev next 的指针,绕过当前节点。

  • 删除当前节点 cur,并更新链表大小 _size

  • 返回下一个节点的迭代器,方便链式操作。

iterator erase(iterator pos)
{
    Node* cur = pos._node;
    Node* next = cur->_next;
    Node* prev = cur->_prev;

    prev->_next = next;
    next->_prev = prev;
    delete cur;
    _size--;

    return iterator(next);// 返回下一位置迭代器
}

3.7 其他函数

push_back pop_back 分别用于尾插和尾删。

  • push_back 调用 insert 在链表末尾插入新节点。

  • pop_back 调用 erase 删除链表末尾的节点。

void push_back(const T& x)
{
    insert(end(), x);
}

void pop_back()
{
    erase(--end());
}

push_front pop_front 分别用于头插和头删。

  • push_front 调用 insert 在链表头部插入新节点。

  • pop_front 调用 erase 删除链表头部的节点。

void push_front(const T& x)
{
    insert(begin(), x);
}

void pop_front()
{
    erase(begin());
}

size 函数返回列表中有效节点的数量。

  • 直接返回链表大小 _size,提供高效的大小查询。

size_t size() const
{
    return _size;
}

empty 函数判断列表是否为空。

  • 检查链表大小 _size 是否为 0,快速判断链表是否为空。

bool empty()
{
    return _size == 0;
}

clear 函数清空列表。

  • 遍历链表,逐个删除节点,直到链表为空。

void clear()
{
    iterator it = begin();
    while (it != end())
    {
        it = erase(it);
    }
}

swap 函数交换两个列表的头节点。

  • 通过交换头节点和大小,高效地交换两个列表的内容。

void swap(list& lt)
{
    std::swap(_head, lt._head);
    std::swap(_size, lt._size);
}

4. 测试代码

void test_list1()
{
    // 基础功能测试
    list lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_back(3);
    lt.push_back(4);
    lt.push_back(5);

    // 遍历输出
    list::iterator it = lt.begin();
    while (it != lt.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;

    // 添加元素
    lt.push_back(10);
    lt.push_back(20);
    lt.push_front(30);
    lt.push_front(40);

    // 使用范围 for 遍历
    for (auto e : lt)
    {
        cout << e << " ";
    }
    cout << endl;

    // 删除元素
    lt.pop_back();
    lt.pop_back();
    lt.pop_front();
    lt.pop_front();

    // 再次遍历输出
    for (auto e : lt)
    {
        cout << e << " ";
    }
    cout << endl;
}


// 自定义类型测试
struct A
{
    int _a1;
    int _a2;

    A(int a1 = 0, int a2 = 0)
        :_a1(a1)
        ,_a2(a2)
    {}
};

void test_list2()
{
    list lt;
    A aa1(2, 2);
    A aa2 = {3, 3};

    lt.push_back(aa1);
    lt.push_back(aa2);
    lt.push_back(A(4, 4));
    lt.push_back({5, 5});
    lt.push_back({6, 6});

    // 遍历输出结构体成员
    list::iterator it = lt.begin();
    while (it != lt.end())
    {
        cout << it->_a1 << ":" << it->_a2 << endl;
        ++it;
    }
}

void PrintList(const list& clt)
{
    list::const_iterator it = clt.begin();
    while (it != clt.end())
    {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
}

void test_list3()
{
    list lt;
    lt.push_back(1);
    lt.push_back(2);
    lt.push_back(3);
    lt.push_back(4);
    lt.push_back(5);

    list lt1(lt);
    PrintList(lt1);
}

5. 源码 

#pragma once // 防止头文件重复包含

#include  // 断言相关函数
#include  // 输入输出流
using namespace std;

namespace lv // 命名空间lv
{
    // 链表节点模板类
    template
    struct ListNode
    {
        ListNode* _next; // 后继指针
        ListNode* _prev; // 前驱指针
        T _data;            // 数据域

        // 构造函数,初始化节点,默认数据为T类型的默认构造值
        ListNode(const T& x = T())
            :_next(nullptr)
            ,_prev(nullptr)
            ,_data(x)
        {}
    };

    // 链表迭代器模板类(泛型设计,支持普通/const迭代器)
    template
    struct ListIterator
    {
        typedef ListNode Node;          // 节点类型别名
        typedef ListIterator Self; // 自身类型别名

        Node* _node; // 当前节点指针

        // 构造函数,用给定节点指针初始化迭代器
        ListIterator(Node* node)
            :_node(node)
        {}

        // 解引用运算符,返回数据引用(Ref可能是T&或const T&)
        Ref operator*()
        {
            return _node->_data;
        }

        // 箭头运算符,返回数据指针(Ptr可能是T*或const T*)
        Ptr operator->()
        {
            return &_node->_data;
        }

        // 前置++,移动到下一个节点
        Self& operator++()
        {
            _node = _node->_next;
            return *this;
        }

        // 后置++,返回旧值并移动到下一个节点
        Self operator++(int)
        {
            Self tmp(*this);
            _node = _node->_next;
            return tmp;
        }

        // 前置--,移动到前一个节点
        Self& operator--()
        {
            _node = _node->_prev;
            return *this;
        }

        // 后置--,返回旧值并移动到前一个节点
        Self operator--(int)
        {
            Self tmp(*this);
            _node = _node->_prev;
            return tmp;
        }

        // 比较运算符,判断两个迭代器是否指向不同节点
        bool operator!=(const Self& it) const
        {
            return _node != it._node;
        }

        // 比较运算符,判断两个迭代器是否指向相同节点
        bool operator==(const Self& it) const
        {
            return _node == it._node;
        }
    };

    // 双向链表模板类
    template
    class list
    {
        typedef ListNode Node; // 节点类型别名
    public:
        // 迭代器类型定义
        typedef ListIterator iterator;             // 可修改迭代器
        typedef ListIterator const_iterator; // 不可修改迭代器

        // 获取指向第一个元素的迭代器
        iterator begin()
        {
            return _head->_next;
        }

        // 获取尾后迭代器(指向头节点)
        iterator end()
        {
            return _head;
        }

        // 获取指向第一个元素的const迭代器
        const_iterator begin() const
        {
            return _head->_next;
        }

        // 获取尾后const迭代器
        const_iterator end() const
        {
            return _head;
        }

        // 初始化空链表(创建头节点并自环)
        void empty_init()
        {
            _head = new Node;      // 创建头节点
            _head->_next = _head;  // 后继指向自己
            _head->_prev = _head;  // 前驱指向自己
            _size = 0;             // 初始化元素个数
        }

        // 默认构造函数
        list()
        {
            empty_init();
        }

        // 拷贝构造函数(深拷贝)
        list(const list& lt)
        {
            empty_init();
            for (const auto& e : lt) // 遍历源链表元素
            {
                push_back(e);       // 将元素逐个插入新链表
            }
        }

        // 交换两个链表的内容
        void swap(list& lt)
        {
            std::swap(_head, lt._head); // 交换头指针
            std::swap(_size, lt._size); // 交换元素个数
        }

        // 赋值运算符(通过拷贝交换实现)
        list& operator=(const list& lt)
        {
            if (this != <) // 防止自赋值
            {
                list tmp(lt); // 拷贝构造临时对象
                swap(tmp);       // 交换当前对象与临时对象
            }
            return *this; // 返回当前对象
        }

        // 清空链表所有元素
        void clear()
        {
            iterator it = begin();
            while (it != end()) // 遍历删除所有元素
            {
                it = erase(it);
            }
        }

        // 析构函数
        ~list()
        {
            clear();        // 清空元素
            delete _head;   // 释放头节点
            _head = nullptr;
        }

        // 在链表尾部插入元素
        void push_back(const T& x)
        {
            insert(end(), x); // 在end()前插入
        }

        // 在链表头部插入元素
        void push_front(const T& x)
        {
            insert(begin(), x); // 在begin()前插入
        }

        // 删除尾部元素
        void pop_back()
        {
            erase(--end()); // 删除end()的前一个元素
        }

        // 删除头部元素
        void pop_front()
        {
            erase(begin()); // 删除第一个元素
        }

        // 在pos位置前插入元素
        iterator insert(iterator pos, const T& val)
        {
            Node* cur = pos._node;  // 当前节点
            Node* newnode = new Node(val); // 创建新节点
            Node* prev = cur->_prev; // 前驱节点

            // 调整指针连接
            prev->_next = newnode;
            newnode->_prev = prev;
            newnode->_next = cur;
            cur->_prev = newnode;

            _size++; // 元素计数增加
            return iterator(newnode); // 返回指向新节点的迭代器
        }

        // 删除pos位置的元素
        iterator erase(iterator pos)
        {
            assert(pos != end()); // 确保不删除头节点

            Node* cur = pos._node; // 当前节点
            Node* next = cur->_next; // 后继节点
            Node* prev = cur->_prev; // 前驱节点

            // 调整指针连接
            prev->_next = next;
            next->_prev = prev;
            delete cur;     // 释放节点

            _size--;        // 元素计数减少
            return iterator(next); // 返回后继节点的迭代器
        }

        // 获取链表元素个数
        size_t size() const
        {
            return _size;
        }

        // 判断链表是否为空
        bool empty()
        {
            return _size == 0;
        }

    private:
        Node* _head;  // 头节点指针
        size_t _size; // 元素个数
    };
}

你可能感兴趣的:(C++,c++,list,list,模拟实现)