C++手动实现list


在该部分我们将会实现C++中的list,如果对list相关知识不太了解,可以看一下之前总结过list的相关知识:C++容器:list

list中的成员函数总结

函数名功能
list()构造函数
~list()析构函数
list(const list& li)拷贝构造函数
list& operator=(const list& li)赋值运算符重载函数
void push_back(value_type val)向list对象尾部增添元素
void pop_back()删除list对象最后一个元素
void push_front(const_reference val)向list对象头部增添元素
void pop_front()删除list对象第一个元素
data_type front()const取出list对象中的第一个元素
data_type back()const取出list对象中的最后一个元素
iterator begin()获取list实例化对象的元素首地址
iterator end()获取list实例化对象的最后一个元素的下一个地址
size_t size()const获取list实例化对象的元素个数
bool empty() const判断list实例化对象是否为空
void clear()清空list中的元素

list中的成员变量

首先为了实现list可以实例化任意数据类型的对象,我们需要对它进行模板化,在类的定义之前增加如下语句:

template<typename T>

如我们想要实例化一个int型list的时候,使用list<int> li,此时模板中的T就是指int型数据类型,那么T*就是指int*数据类型。

我们可以在类中给这些和T相关的类型使用typedef起别名,代码如下:

public:
    typedef T data_type;
    typedef size_t  size_type;
    typedef T& refernce;
    typedef T* pointer;
    typedef const T& const_reference;
    typedef const T* const_pointer;

list本质上其实就是我们链表,以下就是我们实现list所用到的成员变量:

  • node: 节点,一个结构体,用于存放数据
  • _head: 头指针,指向list中的第一个节点
  • _tail : 尾指针,指向list中的最后一个节点
  • _size: list对象中的含有数据的节点个数

该部分相关代码如下:

private:
    struct node{  // 嵌套类结构体
        data_type data;
        node* _next;
        node* _prev;
        node():_next(NULL), _prev(NULL) {}
    };
    node* _head;
    node* _tail;
    size_type _size;

list的迭代器iterator

容器的迭代器用于遍历容器中的每一个元素,同时避免容器的内部数据结构和实现细节。迭代器的意义就是将容器与算法解除耦合,或者说是让数据与操作解除耦合。算法可以利用迭代器作为输入从而摆脱对容器具体数据的访问。

我们主要讲解一下关于对于迭代器it,自加和自减的具体实现,以前缀和后缀为两类。对于前缀即++it, --it,该表达式的值和it的值保持统一,我们直接改变该结点_cur的指向,返回this指针即可;但是对于后缀it++, it--,表达式的值是未改变前it的值,it将会进行更新,故而我们需要将_cur的值保存进一个临时变量,再更新_cur,返回临时变量。在实现的过程中,函数名中的圆括弧中有int的为后缀加减。

具体实现如下:

    class iterator {
        node* _cur;
    public:
        iterator(node* cur):_cur(cur){}
        data_type& operator*(){
           return _cur->data;
        }

        data_type* operator->(){
           return &_cur->data;
        }
        iterator operator++(){
           _cur = _cur->_next;
           return *this;
        }
        iterator operator--(){
           _cur = _cur->_prev;
           return *this;
        }
        iterator operator++(int){
           iterator temp(_cur);
           _cur = _cur->_next;
           return temp;
        }
        iterator operator--(int){
           iterator temp(_cur);
           _cur = _cur->_prev;
           return temp;
        }
        bool operator==(const iterator& it)const{
            return _cur == it._cur;
        }
        bool operator!=(const iterator& it)const{
            return _cur != it._cur;
        }
};

重要代码图解

我们在对list对象进行初始化的时候增加一个temp节点,使得链表的处理更加的简单统一。

    list(): _size(0){
        _head = _tail = new node;
    }

这一部分主要涉及双向链表的插入和删除问题,指针改向的顺序需要注意,如果顺序错误,就会挂链失败。

头插 – push_front

头插具体过程如图所示:下图第一个节点是temp节点,我们进行头插的时候将新的节点挂在该结点和下一个节点中间即可。

在这里插入图片描述

代码如下:

    void push_front(const_reference val) {
        node* cur = new node;
	    cur->data = val;
	    cur->_next = _head->_next;
	    cur->_prev = _head;
	    if(NULL == _head->_next) _tail = cur;
	    else _head->_next->_prev = cur;
	    _head->_next = cur;
	    ++_size;
    }

头删 – pop_front

头删具体过程如图所示:图第一个节点是temp节点,我们进行头删的时候删除的是该结点的下一个节点。

在这里插入图片描述
代码如下:

    void pop_front() {
        if(empty())  return;
	    node* first = _head->_next;
	    _head->_next = first->_next;
	    if(NULL == first->_next) _tail = _head;
	    else first->_next->_prev = _head;
	    delete first;
	    --_size;
    }

尾插 – push_back

具体过程如图所示:

在这里插入图片描述

代码如下:

    void push_back(const_reference val){
        node* cur = new node;
	    cur->data = val;
	    cur->_next = NULL;
	    cur->_prev = _tail;
	    _tail->_next = cur;
	    _tail = cur;
	    ++_size;
    }

尾删 – pop_back

在这里插入图片描述

    void pop_back() {
	    if(empty()) return;
        node* _prev = _tail->_prev;
        delete _tail;
        _prev->_next = NULL;
	    _tail = _prev;
	    --_size;
    }

代码总结

#include <iostream>
using namespace std;

namespace miniSTL{
template<typename T>
class list{
public:
    typedef T data_type;
    typedef size_t  size_type;
    typedef T& refernce;
    typedef T* pointer;
    typedef const T& const_reference;
    typedef const T* const_pointer;
private:   
    struct node{  // 嵌套类结构体
        data_type data;
	    node* _next;
	    node* _prev;
	    node():_next(NULL), _prev(NULL) {}
    };
    node* _head;
    node* _tail;
    size_type _size;
public:
    list(): _size(0){
        _head = _tail = new node;
    }
    list(const list& li){
        _head = _tail = new node;
	    node* p = li._head->_next;
	    while(p!=NULL){
	        push_back(p->data);
	        p = p->_next;
	    }
    }
    list& operator=(const list& li){
        if(this == &li) return *this;
	    clear();
	    node* p = li._head->_next;
	    while(p!=NULL){
	        push_back(p->data);
	        p = p->_next;
	    }
	    return *this;
    }
    void clear(){
	    node* p = _head->_next;
	    while(p!=NULL){
	        node* del = p;
	        p = p->_next;
	        delete del;
	    }
	    _tail = _head;
	    _size = 0;
    }
    ~list(){
        node* p = _head;
	    while(p!= NULL){
	        node* del = p;
	        p = p->_next;
	        delete del;
	    }
	    _size = 0;
    }
    size_type size() const { return _size; }
    bool empty() const { return _size == 0; }
    data_type front()const{ return _head->_next->data; }
    data_type back()const{ return _tail->data;}
    void push_back(const_reference val){
        node* cur = new node;
	    cur->data = val;
	    cur->_next = NULL;
	    cur->_prev = _tail;
	    _tail->_next = cur;
	    _tail = cur;
	    ++_size;
    }

    void pop_back() {
	    if(empty()) return;
        node* _prev = _tail->_prev;
        delete _tail;
        _prev->_next = NULL;
	    _tail = _prev;
	    --_size;
    }

    void push_front(const_reference val) {
        node* cur = new node;
	    cur->data = val;
	    cur->_next = _head->_next;
	    cur->_prev = _head;
	    if(NULL == _head->_next) _tail = cur;
	    else _head->_next->_prev = cur;
	    _head->_next = cur;
	    ++_size;
    }

    void pop_front() {
        if(empty())  return;
	    node* first = _head->_next;
    	_head->_next = first->_next;
    	if(NULL == first->_next) _tail = _head;
	    else first->_next->_prev = _head;
	    delete first;
	    --_size;
    }


    void Print()const{
        node* p = _head->_next;
	    while(NULL != p){
	        cout << p->data << " ";
	        p = p->_next;
	    }
	    cout << endl;
	    p = _tail;
	    while(_head!= p){
	        cout << p->data << " ";
	        p = p->_prev;
	    }
	    cout << endl;
    }

    // 迭代器
    
    class iterator {
        node* _cur;
    public:
	    iterator(node* cur):_cur(cur){}
        data_type& operator*(){
           return _cur->data;  
	    }

        data_type* operator->(){
           return &_cur->data;  
	    }
	    iterator operator++(){
	       _cur = _cur->_next;
	       return *this;
	    }
	    iterator operator--(){
	       _cur = _cur->_prev;
	       return *this;
	    }
	    iterator operator++(int){
	       iterator temp(_cur);
	       _cur = _cur->_next;
	       return temp;
	    }
	    iterator operator--(int){
	       iterator temp(_cur);
	       _cur = _cur->_prev;
	       return temp;
	    }
	    bool operator==(const iterator& it)const{
	        return _cur == it._cur;
	    }    
	    bool operator!=(const iterator& it)const{
	        return _cur != it._cur;
	    }
  };

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

using namespace miniSTL;
int main(){
    list<string> li;
    string n;
    while(cin >> n){
        // li.push_back(n);
        li.push_front(n);
    }

    list<string>::iterator it = li.begin();
    // cout << (it->data) << endl;
    while(it!=li.end()){
        cout << *it << " ";
	++it;
    }
    cout << endl;

    for(auto n:li){
        cout << n << " ";
    }
    cout << endl;

    list<string> li2 = li;
    list<string> li3;
    li3 = li;
    for(auto n:li3){
        cout << n << " ";
    }
    cout << endl;


    /*
    li.Print();

    while(!li.empty()){
        // li.pop_front();
	li.pop_back();
	li.Print();
    }
    */
}
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值