C++:STL——List的模拟实现
Posted It‘s so simple
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++:STL——List的模拟实现相关的知识,希望对你有一定的参考价值。
1. List的介绍和使用
1.1 List的介绍
- list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。
- list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。
- list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。
- 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。
- 与其他序列式容器相比,list和forward_list最大的缺陷是不支持任意位置的随机访问,比如:要访问list的第6个元素,必须从已知的位置(比如头部或者尾部)迭代到该位置,在这段位置上迭代需要线性的时间开销;list还需要一些额外的空间,以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这可能是一个重要的因素)
更为详细的可以查看list文档介绍。
1.2 List类一些接口的使用
list的构造函数
list迭代器的使用
- begin与end为正向迭代器,对迭代器执行++操作,迭代器向后移动
- rbegin(end)与rend(begin)为反向迭代器,对迭代器执行++操作,迭代器向前移动
list capacity
list element access
list modifiers
list其他一些比较常用的接口
assign
:将新内容分配到 list 中,替换其当前内容,并相应地修改其大小。(相当于是复制)merge
:将x合并到列表中,将其所有的元素在各自的有序位置转移到list中(两个list都应该是有序的,并且该操作相当于剪切)。unique
:从list中每一组连续的相等元素中删除除第一个元素以外的所有元素。注意,只有当一个元素与紧随其后的元素比较相等时,才会从list中移除。因此,这个函数对排序的列表特别有用。sort
:对list中的元素进行排序,改变它们在list中的位置。reverse
:反转list中元素的顺序。remove
:从list中移除所有等于val的元素。这将调用这些对象的析构器,并通过移除的元素数量减少容器的大小。resize
:调整list的大小,使其包含n个元素。如果n小于当前list的大小,内容就被缩减到最初的n个元素,删除那些超出的元素(并销毁它们)。如果n大于当前list的大小,内容将被扩展,在最后插入尽可能多的元素以达到n的大小。
2. List的模拟实现
代码如下:
#include <iostream>
#include <cstdlib>
using namespace std;
namespace myTest
{
template <class _Ty>
class List{
protected:
typedef size_t _Size;
struct _Node;
typedef _Node* _Nodeptr;
struct _Node
{
_Nodeptr _Next,_Prev;
_Ty value;
};
struct _ACC
{
typedef _Node*& _Nodepref;
typedef _Ty& _Vref;
static _Nodepref _Next(_Nodeptr _S)
{
return _S->_Next;
}
static _Nodepref _Prev(_Nodeptr _S)
{
return _S->_Prev;
}
static _Vref _Value(_Nodeptr _S)
{
return _S->value;
}
};
_Nodeptr _BuyListNode(_Nodeptr Narg = 0,_Nodeptr Parg = 0)
{
_Nodeptr _S = (_Nodeptr) malloc(sizeof(_Node));
_ACC::_Next(_S) = Narg != 0 ? Narg : _S;
_ACC::_Prev(_S) = Parg != 0 ? Parg : _S;
return _S;
}
void _FreeNode(_Nodeptr _S)
{
free(_S);
}
public:
class iterator
{
public:
iterator()
{
cout << "Over create iterator!" << endl;
}
iterator(_Nodeptr ptr) : _Ptr(ptr)
{}
iterator(const iterator &_it)
{
this->_Ptr = _it._Ptr;
}
bool operator!=(iterator& _it) const
{
return _Ptr != _it._Ptr;
}
bool operator==(iterator& _it) const
{
return!(*this!=_it);
}
iterator& operator++()
{
_Ptr = _ACC::_Next(_Ptr);
return *this;
}
iterator operator++(int)
{
iterator tmp(*this);
++(*this);
return tmp;
}
_Ty operator*()
{
return _ACC::_Value(_Ptr);
}
iterator& operator--()
{
_Ptr = _ACC::_Prev(_Ptr);
return *this;
}
iterator operator--(int)
{
iterator tmp(*this);
--(*this);
return tmp;
}
_Nodeptr _MyNode()
{
return _Ptr;
}
private:
_Nodeptr _Ptr;
};
public:
explicit List():Head(_BuyListNode()),_size(0)
{
_ACC::_Next(Head) = Head;
_ACC::_Prev(Head) = Head;
cout << "Over create List<class _Ty>" << endl;
}
List(_Size _n,const _Ty& _V = _Ty() ):Head(_BuyListNode()),_size(0)
{
insert(begin(),_n,_V);
}
List(const _Ty* _f,const _Ty* _l):Head(_BuyListNode()),_size(0)
{
insert(begin(),_f,_l);
}
~List()
{
clear();
_FreeNode(Head);
Head=0,_size=0;
}
public:
_Size size() const
{
return _size;
}
bool empty()const
{
return _size==0;
}
_Ty& front()
{
return *begin();
}
const _Ty& front() const
{
return *begin();
}
_Ty& back()
{
return *(--end());
}
void push_back(const _Ty& _val)
{
insert(end(),_val);
}
void push_front(const _Ty& _val)
{
insert(begin(),_val);
}
/*
void push_back(_Ty val)
{
_Nodeptr _tmp = _BuyListNode(Head,Head->_Prev);
_ACC::_Value(_tmp) = val;
_ACC::_Prev(_ACC::_Next(_tmp)) = _tmp;
_ACC::_Next(_ACC::_Prev(_tmp)) = _tmp;
size++;
cout << "push_back access" << endl;
}
*/
iterator begin()const
{
return iterator(_ACC::_Next(Head));
}
iterator end() const
{
return iterator(Head);
}
iterator insert(iterator _it,_Ty val= _Ty())
{
_Nodeptr _S = _it._MyNode();
_ACC::_Prev(_S) = _BuyListNode(_S,_ACC::_Prev(_S));
_S = _ACC::_Prev(_S);
_ACC::_Value(_S) = val;
_ACC::_Next(_ACC::_Prev(_S)) = _S;
++_size;
cout << "iterator insert success!" << endl;
return iterator(_S);
}
iterator erase(iterator _it)
{
_Nodeptr _S = (_it++)._MyNode();
_ACC::_Next(_ACC::_Prev(_S)) = _ACC::_Next(_S);
_ACC::_Prev(_ACC::_Next(_S)) = _ACC::_Prev(_S);
--_size;
_FreeNode(_S);
return _it;
}
void insert(iterator _it,_Size _M,const _Ty& _x)
{
for(;0 < _M; --_M)
insert(_it,_x);
}
void insert(iterator _it,const _Ty* _f,const _Ty* _l)
{
while(_f!=_l)
{
insert(_it,*_f++);
}
}
iterator erase(iterator _itbegin, iterator _itend)
{
while(_itbegin != _itend)
{
erase(_itbegin++);
}
return _itbegin;
}
void clear()
{
erase(begin(),end());
}
private:
_Nodeptr Head;
_Size _size;
};
}
void test1()
{
myTest::List<int> mylist;
mylist.push_back(1);
mylist.push_back(2);
}
void test2()
{
myTest::List<int> mylist;
mylist.push_back(1);
mylist.push_back(2);
myTest::List<int>::iterator it1 = mylist.begin();
myTest::List<int>::iterator it2 = mylist.end();
while(it1 != it2)
{
cout << *it1 << "->";
++it1;
}
cout << "over print to iterator!" << endl;
}
void test3()
{
int ar[] = {1,2,3,4,5,6,7,8,9,10};
myTest::List<int> mylist(ar, ar+10);
//mylist.erase(mylist.begin(), mylist.end()); //[ )
// mylist.clear();
myTest::List<int>::iterator it = mylist.begin();
myTest::List<int>::iterator it1 = mylist.end();
while(it != it1)
{
cout<<*it<<"-->";
++it; //it++
}
cout<<"Over."<<endl;
}
int main()
{
//test1();
//test2();
test3();
return 0;
}
3. List实现的不成文规定
- 若定义的成员变量,只供自己内部使用,则需要加上下划线,例如:
_Nodeptr Head;
。 - 双向循环链表的最后一个节点是头节点。
- 插入时,是在迭代器的前面进行插入。
- end迭代器永远指向最后一个元素的下一个位置。
以上是关于C++:STL——List的模拟实现的主要内容,如果未能解决你的问题,请参考以下文章
C++初阶:STL —— listlist的介绍及使用 | list的深度剖析及模拟实现 | list与vector的对比
C++初阶:STL —— listlist的介绍及使用 | list的深度剖析及模拟实现 | list与vector的对比
C++初阶:STL —— listlist的介绍及使用 | list的深度剖析及模拟实现 | list与vector的对比