C++容器中list总结及其实现
程序员文章站
2022-03-04 14:37:09
...
list
list为双向带头循环链表,由若干结点组成,每个结点都包含一个数据块,前驱指针和后驱指针。list存储在非连续的空间之中,所以相较vector来说list的随机检索能力很弱,检索时间复杂度为O(n)。
优点:
-
插入,删除元素的代价较小
-
可在两端进行操作
-
不需要连续的内存空间
缺点: -
不支持随机访问 [ ], at
-
内存占用多
相关使用函数:
push_back 尾插
pop_back 尾删
push_front 头插
pop_front 头删
erase 删除指定位置结点
insert 指定位置插入结点
clear 清空list
size 结点个数
resize 重新规定结点个数
swap 交换两个链表
emplace_front 头插(默认构造函数)
emplace_back 尾插(默认构造函数)
splice 合并list
unique 去重
sort 排序(默认从小到大)
merge 按大小合并
reverse 反转
具体请看 http://www.cplusplus.com/reference/list/list/
list迭代器的实现:
利用原生指针进行封装,生成一个自定义类。
template<class T> //结点
struct ListNode{
ListNode(const T& val = T())
:_val(val)
,_pre(nullptr)
,_next(nullptr)
{}
T _val;
ListNode<T>* _pre;
ListNode<T>* _next;
};
template<class T, class Pre, class Arc> //实现iterator类
class _ListIterator{
public:
typedef ListNode<T> Node;
typedef _ListIterator<T,Pre,Arc> Self; //Pre 为T& Arc为T*
public:
Node* _node;
_ListIterator(Node* node)
:_node(node)
{
}
Arc operator*() //迭代器解引用是获取数据
{
return _node->_val;
}
Pre operator->() //迭代器的->返回的为数据的指针
{
return &(_node->_val);
}
Self& operator++() //后置++
{
_node = _node->_next;
return *this;
}
Self operator++(int) //前置++
{
Self tmp(*this);
_node = _node->_next;
return tmp;
}
Self& operator--()
{
_node= _node->_pre;
return *this;
}
Self operator--(int)
{
Self tmp(*this);
_node = _node->_pre;
return tmp;
}
Self& operator+(size_t n)
{
for(int i =0; i<n; ++i)
{
_node = _node->_next;
}
return *this;
}
bool operator!=(const Self& l)
{
return _node!=l._node;
}
bool operator==(const Self& l)
{
return _node==l._node;
}
};
list的部分功能的实现:
template<class T>
class List{
typedef ListNode<T> Node;
public:
typedef _ListIterator<T,T*,T&> iterator;
typedef _ListIterator<T,const T*, const T&> const_iterator;
List()
:_head(new Node)
{
_head->_next = _head;
_head->_pre = _head;
}
~List()
{
if(_head)
{
Clear();
delete _head;
_head = nullptr;
}
}
List(List<T>& l) //拷贝构造 深拷贝
{
_head = new Node;
_head->_next = _head;
_head->_pre = _head;
for(auto&e : l)
{
PushBack(e);
}
}
List<T>& operator=(const List<T> l) //传参时进行了拷贝构造
{
swap(_head,l._head);
return *this;
}
void Clear() //清空
{
if(_head)
{
Node* cur = _head->_next;
while(cur != _head)
{
Node* next =cur->_next;
delete cur;
cur = next;
}
_head->_next = _head;
_head->_pre = _head;
}
}
void PushBack(const T& val) //尾插
{
Node* cur = new Node(val);
Node* pre = _head->_pre;
cur->_pre = pre;
cur->_next = _head;
pre->_next = cur;
_head->_pre = cur;
}
void PopBack() //尾删
{
Node* cur = _head->_pre;
cur->_pre->_next = _head;
_head->_pre = cur->_pre;
delete cur;
}
void PushFront(const T& val) //头插
{
Node* cur = new Node(val);
Node* next = _head->_next;
next->_pre = cur;
cur->_next = next;
cur->_pre = _head;
_head->_next = cur;
}
void PopFront() //头删
{
Node* cur = _head->_next;
cur->_next->_pre = _head;
_head->_next = cur->_next;
delete cur;
}
void Insert(iterator pos, const T& val) //迭代器位置插入
{
Node* cur = new Node(val);
Node* _pos = pos._node;
_pos->_pre->_next = cur;
cur->_pre = _pos->_pre;
cur->_next = _pos;
_pos->_pre = cur;
}
//删除迭代器失效
iterator Erase(iterator pos)
{
if (pos != end())
{
Node* cur = pos._node;
Node* prev = cur->_pre;
Node* next = cur->_next;
prev->_next = next;
next->_pre = prev;
delete cur;
cur = nullptr;
pos = iterator(next);
}
return pos;
}
iterator begin() //普通迭代器
{
return iterator(_head->_next);
}
iterator end()
{
return iterator(_head);
}
const_iterator begin()const //const迭代器
{
return const_iterator(_head->_next);
}
const_iterator end()const
{
return const_iterator(_head);
}
bool Empty()
{
return _head==_head->_next;
}
size_t Size()
{
size_t sz = 0;
Node *cur = _head->_next;
while(cur != _head)
{
sz++;
cur = cur->_next;
}
return sz;
}
void Resize(size_t num, const T& val = T())
{
size_t sz = Size();
if(sz<=num)
{
for(int i =sz; i<num; ++i)
{
PushBack(val);
}
}else
{
for(int i=0; i<num-sz; ++i)
{
PopBack();
}
}
}
T& Front() //返回链表第一个元素
{
return _head->_next->_val;
}
T& Back() //返回链表最后一个元素
{
return _head->_pre->_val;
}
const T& Front()const
{
return _head->_next->_val;
}
const T& Back()const
{
return _head->_pre->_val;
}
private:
Node* _head;
};
还有部分功能后面有时间再进一步实现。
上一篇: Visual Studio 编译选项
下一篇: 修改table高度