自学内容网 自学内容网

C++list的模拟实现

基本结构

首先明确一个问题,list是带头双向循环链表,既然是链表,那么我们就需要定义一个节点的结构体,然后既然是list的模拟实现,就需要定义一个list的类,根据带头双向循环链表的特点,还需要一个头节点,所以list的成员变量中必有一个头节点

下面是基本结构

namespace bit
{
    template<class T>
    struct ListNode
    {
        ListNode<T>* _next;
        ListNode<T>* _prev;
        T _Date;
        ListNode(const T x=T())
        {
            _next=nullptr;
            _prev=nullptr;
            _Date=x;
        }
    };


    
    template<class T>
    calss list
    {
     public:
     list()
     {
        _head=new Node;
        _head->_next=_head;
        _head->_prev=_head;
     }

     private:
     typedef ListNode<T> Node;
     Node* _head;
        
    };


}

上面有一个问题,上面的那个定义节点要用struct,而不用class,原因就是上面的节点里面的任何元素随时都需要访问, 而struct里面的是默认共有的,当然在这里你也可以用calss,只是需要把所有的元素置成公有的

push_back()

向节点的尾部添加一个节点,基本的思路就是找到尾节点,申请新的节点,然后将新的节点连接就行了

void push_back(const T x)
{
Node* tail = _head->_prev;
Node* newnode = new Node(x);
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
}

迭代器

今天的这个迭代器会有一点特别,以前在string,vector里面的模拟实现里面,定义一个迭代器都是都是直接typedef一个int*,或者一个char*,让后直接对迭代器进行++或者--,但是,今天的这个是链表,结构在物理上都不是连续的,如何进行++或者--操作,这是不行的,唯一的方法就是对定义一个迭代器的类,然后对++或者--进行操作符的重载


template<class T>
class ListIterator
{

typedef ListNode<T> Node;
typedef ListIterator<T> self;
Node* _node;

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


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

self operator++(int)
{
self temp(_node);
_node = _node->_next;
return temp;
}

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

self operator--(int)
{
self temp(_node);
_node = _node->_prev;
return temp;
}


bool operator==(const self& s)
{
return _node == s._node;
}
bool operator!=(const self& s)
{
return _node != s._node;
}

T& operator*()
{
return _node->_Date;
}

T* operator->()
{
return &(_node->_Date);
}


};

这样就可以对链表进行遍历了,当然了,这里的的begin()和end()函数还没有实现,可以在下面完整代码的list里面去查看

上面代码还有一个问题,你迭代器里面去重载一个—>有什么用

主要是为下面的情况做准备的

上面又又同学问了,啊,->这个操作符得出不是pos的地址吗,你这个怎么好直接就能去的出pos里面的成员变量的,其实上面的写法和被注释掉的代码是一样的,这里编译器是为了增强代码的可读性和美观性才这样省略出这样的, 

const迭代器

const迭代器和非const迭代器其实是相差不大的,有人可能认为,在iterator前面加上一个const让他变成const iterator不就成为const迭代器了吗,那你就大错特错了

const迭代器是什么?是迭代器里面指向的内容不能被修改,直接加const不久变成迭代器不能被修改了,这里其实代码和非const迭代器是差不多的,唯一有一个地方需要改的就是限制解引用的返回值,让他变成const

template<class T>
class ListConstIterator
{

typedef ListNode<T> Node;
typedef ListConstIterator<T> self;
Node* _node;

public:
ListConstIterator(Node* node)
:_node(node)
{}


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

self operator++(int)
{
self temp(_node);
_node = _node->_next;
return temp;
}

bool operator==(const self& s)
{
return _node == s._node;
}
bool operator!=(const self& s)    //记得参数里面加const,如果不加,会出现权限的放大问题
{
return _node != s._node;
}

const T& operator*()          //加const
{
return _node->_Date;
}

const T* operator->()        //加const
{
return &(_node->_Date);
}


};

两个迭代器合一块

两个迭代器写一块,那不是太麻烦了一点,能不能写一个模板?答案是可以的

只需要在模板参数里面添加两个参数

然后下面函数的返回值稍微改动一下

最后关键的一步来了

 

在list定义迭代器里面的时候给不同的模板参数就行了

析构函数


~list()
{
list<T>::iterator it = begin();
while (it != end())
{
it = erase(it);
}

delete _head;
_head = nullptr;
}

拷贝构造和赋值重载

void empty_init()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}


list<T>& operator=(const list<T> l1)
{
empty_init();                //这里记着要初始化
swap(_head, l1._head);
return *this;
}

 上面的赋值运算符重载设计得很巧妙,首先明确的一个问题是要使用传值传参,后面直接交换两个_head的指向,因为传值传参会引发拷贝构造函数,后面把_head的指向给l1的拷贝构造了之后函数结束直接析构,这里就有点像让你干活,最后把你给杀了

list(const list<T>& l1)
{
empty_init();
for (const auto &e : l1)
{
push_back(e);
}


}

 这里记得拷贝构造函数需要使用深拷贝,如果你不写拷贝构造函数得话,编译器生成的默认构造函数默认的是浅拷贝,函数调用结束了之后会发生同一块空间析构两次的问题,导致程序崩溃

写代码时的一个易错点

这里写代码的时候老是出现下面的问题:函数匹配问题,这一般都是由于权限的放大缩小问题

还有就是写范围for的时候尽量写引用,因为范围for实际上时赋值给e,赋值的话会拷贝产生一个临时对象,如果auto是自定义类型的话,拷贝量太大了,效率比较低

常规函数

void erase(iterator pos)            //迭代器失效,因为被释放了
{
Node* prev = pos._node->_prev;
Node* next = pos._node->_next;
prev->_next = next;
next->_prev = prev;
delete pos._node;
pos._node = nullptr;
}

void insert(iterator&pos, T x)       //迭代器没有失效
{
Node* newnode = new Node(x);
Node* prev = pos._node->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos._node;
pos._node->_prev = newnode;
}

void pop_back()
{
Node* cur = _head->_prev;
Node* prev = cur->_prev;
prev->_next = _head;
_head->_prev = prev;
delete cur;
}

完整代码

#include<iostream>
using namespace std;
namespace bit
{
template<class T>
struct ListNode
{
ListNode<T>* _next;
ListNode<T>* _prev;
T _Date;

ListNode(const T date = T())
:_Date(date)
,_prev(nullptr)
,_next(nullptr)
{

}

};


template<class T,class ref,class ptr>
class ListIterator
{

typedef ListNode<T> Node;
typedef ListIterator<T,ref,ptr> self;
public:
Node* _node;
public:
ListIterator(Node* node)
:_node(node)
{

}

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

}

self operator++(int)
{
self temp(_node);
_node = _node->_next;
return temp;
}

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

bool operator==(const self& s)
{
return _node == s._node;
}

bool operator!=(const self& s)
{
return _node != s._node;
}

ref&operator*()
{
return _node->_Date;
}

ptr operator->()
{
return &(_node->_Date);
}

};

/*template<class T>
class ListConstIterator
{

typedef ListNode<T> Node;
typedef ListConstIterator<T> self;
Node* _node;

public:
ListConstIterator(Node* node)
:_node(node)
{}


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

self operator++(int)
{
self temp(_node);
_node = _node->_next;
return temp;
}

bool operator==(const self& s)
{
return _node == s._node;
}
bool operator!=(const self& s)
{
return _node != s._node;
}

const T& operator*()
{
return _node->_Date;
}

T* operator->()
{
return &(_node->_Date);
}


};*/


template<class T>
class list
{
public:
typedef ListIterator<T, T&,T*> iterator;
typedef ListIterator<T, const T&, const T*> const_iterator;
//typedef ListConstIterator<T> const_iterator;
iterator begin()
{
return iterator(_head->_next);
}

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

        const_iterator end()const
{
return const_iterator(_head);
}

iterator end()
{
return iterator(_head);
}

void empty_init()
{
_head = new Node;
_head->_next = _head;
_head->_prev = _head;
}


list<T>& operator=(const list<T> l1)
{
empty_init();
swap(_head, l1._head);
return *this;
}

list()
{
empty_init();
}
void push_back(const T x)
{
Node* tail = _head->_prev;
Node* newnode = new Node(x);
tail->_next = newnode;
newnode->_prev = tail;
newnode->_next = _head;
_head->_prev = newnode;
}

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

return iterator(next);
}

list(const list<T>& l1)
{
empty_init();
for (const auto &e : l1)
{
push_back(e);
}


}

~list()
{
list<T>::iterator it = begin();
while (it != end())
{
it = erase(it);
}

delete _head;
_head = nullptr;
}

bool empty()
{
return _head->_next == _head;
}
void insert(iterator&pos, T x)
{
Node* newnode = new Node(x);
Node* prev = pos._node->_prev;
prev->_next = newnode;
newnode->_prev = prev;
newnode->_next = pos._node;
pos._node->_prev = newnode;
}

void pop_back()
{
Node* cur = _head->_prev;
Node* prev = cur->_prev;
prev->_next = _head;
_head->_prev = prev;
delete cur;
}
private:
typedef ListNode<T> Node;
Node* _head;
};

void test01()
{
list<int> l1;
l1.push_back(10);
l1.push_back(20);
l1.push_back(30);
l1.push_back(40);
l1.push_back(50);
l1.push_back(60);
list<int>::iterator it = l1.begin();
while (it != l1.end())
{
cout << *it << " ";
it++;
}
cout << endl;

}

void func(const list<int>&s)
{
list<int>::const_iterator it = s.begin();
while (it != s.end())
{
//(*it)++;
cout << *it << " ";
it++;
}
}

void test02()
{
list<int> l1;
l1.push_back(10);
l1.push_back(20);
l1.push_back(30);
l1.push_back(40);
func(l1);
}

struct pos
{
int _x;
int _y;
pos(int x=0,int y=0)
:_x(x)
,_y(y)
{}
};

void test03()
{
list<pos> p;
p.push_back(pos(1,2));
p.push_back(pos(3,4));
p.push_back(pos(5,6));
list<pos>::iterator it = p.begin();
//cout << it.operator->()->_x << " " << it.operator->()->_y << endl;
cout << it->_x << " " << it->_y << endl;

}

void test04()
{
list<int> l1;
l1.push_back(1);
l1.push_back(2);
l1.push_back(3);
l1.push_back(4);
for (auto &e : l1)
{
cout << e << " ";
}
cout << endl;

list<int> l2 = l1;
for (auto& e : l2)
{
cout << e << " ";
}
cout << endl;


}


void test05()
{
list<int> l1;
l1.push_back(10);
l1.push_back(20);
l1.push_back(30);
l1.push_back(40);

}
}


原文地址:https://blog.csdn.net/lihaolihao111111/article/details/142970777

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!