如何使用list,看如下代码
#include<iostream>
#include<list>
#include<stdlib.h>
#include<functional>
using namespace std;
void PrintList(list<int>& l1)
{
list<int>::iterator it = l1.begin();
while (it != l1.end())
{
cout << *it << " ";
it++;
}
cout << endl;
}
int main()
{
list<int>l1;
l1.push_back(2);
l1.push_back(2);
l1.push_back(3);
l1.push_back(1);
PrintList(l1);
l1.remove(4);//删除不存在的 不报错
l1.remove(2);//删除存在的 不报错
PrintList(l1);
list<int> l2(5, 1);
PrintList(l1);
PrintList(l2);
list<int>::iterator it = l1.begin();
/*while (it != l1.end())//本意想删除刚才插入的所有元素 出错迭代器失效
{ if(*it)
l1.erase(it);
it++;
}*/
while (it != l1.end())
{
if (*it)
{
it = l1.erase(it);//可看出库里面的erase有一个返回值 ,返回的是删除位置下一个位置的迭代器
}
else
{
it++;
}
}
PrintList(l1);
l1.sort();//升序排
l1.unique();//去重,也就是去除连起来的相同的元素 一般和排序sort结合着用
PrintList(l1);
l1.reverse();
PrintList(l1);
l1.sort(greater<int>());//greater是降序,less是升序 头文件是<functional>
cout << endl;
//l1.remove(4);//删除不存在的 不报错
//l1.remove(2);//删除存在的 不报错
//PrintList(l1);
//l1.erase(l1.begin());//删除存在的 不报错
//PrintList(l1);
//l1.erase(l1.end());//删除不存在的 报错
//PrintList(l1);
system("pause");
return 0;
}
注意remove和erase的区别:
remove删除,给一个值,有就删除,没有就不删除
erase 删除,给一个位置,找到就删除,找不到即空位置报错
自己实现的list
#include<iostream>
#include<assert.h>
using namespace std;
template <class T>
struct MyListNode
{
T _data;
MyListNode<T>* _next;
MyListNode<T>* _prev;
MyListNode(const T& x)
: _data(x)
, _next(NULL)
, _prev(NULL)
{
}
};
template<class T,class Ref,class Ptr>
class ListIterator//迭代器是一个类,对结点指针进行封装,通过对类重载operator++,--,*,->,向一个指针一样遍历所有容器,访问,修改,都有统一的方式,学习成本低会用迭代器访问list就会用它访问vector
{
public:
typedef MyListNode<T> Node;
typedef ListIterator<T, Ref, Ptr>Self;
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);//掉拷贝构造 //Self tmp(_node);//掉构造
_node = _node->_next;
return tmp;//此处有一次拷贝构造
}
Self& operator--()
{
_node = _node->_prev;
rturn *this;
}
Self operator--(int)
{
Node* cur = _node;
_node = _node->_prev;
return Self(cur);//这里相对上面实现的operator++(int)少了一次拷贝构造,优化
}
bool operator!=(Self& s)
{
return _node != s._node;
}
bool operator==(Self& s)
{
return _node == s._node;
}
Node* _node;
};
template <class T>
class MyList
{
public:
typedef MyListNode<T> Node;
typedef ListIterator<T, T&, T*> Iterator;
typedef ListIterator<T, const T&, const T*> ConstIterator;
MyList()
{
_head = GetNode(T());//用匿名对象初始化
_head->_next = _head;
_head->_prev = _head;
}
~MyList()
{
Clear();
delete _head;
_head = NULL;
}
void Clear()
{
Iterator it = Begin();
while (it != End())
{
Node* del = it._node;
++it;
delete del;
}
_head->_next = _head;
_head->_prev = _head;
}
void PushBack(const T&x)
{
Node* tail = _head->_prev;
Node* newNode = GetNode(x);
tail->_next = newNode;
newNode->_prev = tail;
newNode->_next= _head;
_head->_prev = newNode;
}
void PopBack()
{
Erase(--End());
}
void PushFront(const T& x)
{
Insert(Begin(),x);
}
void PopFront()
{
Erase(Begin());
}
bool Empty()
{
return _head->_next = _head;
}
Iterator Insert(Iterator pos, const T&x)
{
assert(pos._node);
Node* tmp = GetNode(x);
Node* prev = pos._node->_prev;
Node* next = pos._node->_next;
prev->_next = tmp;
tmp->_prev = prev;
tmp->_next = next;
next->_prev = tmp;
return tmp;
}
Node* GetNode(const T& x)
{
return new Node(x);
}
Iterator Erase(Iterator pos)//注意erase返回的是下一个位置的迭代器
{
assert((pos != End()) && (pos._node));
Node* prev = pos._node->_prev;
Node* next = pos._node->_next;
delete pos._node;
prev->_next = next;
next->_prev = prev;
return Iterator(next);//也可以是return next;隐式类型转换
}
Iterator Begin()
{
return Iterator(_head->_next);//也可以为return _head->_next 隐式类型转换
}
Iterator End()
{
return Iterator(_head);
}
ConstIterator Begin()const
{
return ConstIterator(_head->_next);
}
ConstIterator End() const//相当于返回值是const T* 也就是说明迭代器指向的数据不能被改
{
return ConstIterator(_head);
}
//去重
void Unique()//思路,两个迭代器,一个前,一个后,如果不同,同时向后走,相同删除一个并且走一步,另一个不动,直到快的那个结束
{
Iterator first = Begin();
if (first == End())//没有结点,不用去重
return;
Iterator fast = Iterator(first._node->_next);
while (first != End())
{
if (*first == *fast)
{
fast = Erase(fast);
}
else
{
++first;
++fast;
}
}
}
Iterator Find(const T&x)//Find返回迭代器,不能返回指针 暴露细节
{
Node* cur = _head->_next;
while (cur != _head)
{
if (cur->_data == x)
{
return Iterator(cur);
cur = cur->_next;
}
}
return Iterator(_head);//没找到返回头 不存在的迭代器
}
void Remove(const T& x)//删除
{
Iterator first = Begin();
while (first != End())
{
if (*first == x)
{
first=Erase(first);
}
else
{
++first;
}
}
}
private:
Node* _head;
};
//void PrintList(const MyList<int>& l1)//参数有const修饰,只需实现如下有const修饰的Begin()和End()即可,通过编译。思考?为什莫还要ConstIterator呢?
//原因在于,虽然这样可以编译通过,但是普通迭代器,*it数据可以被改变,但是我们之所以加const就是不希望被改变。因此有了ConstIterator
//{
// MyList<int>::Iterator it = l1.Begin();
// while (it != l1.End())
// {
// *it = 10;//此处不报错 可以被改变
// cout << *it << " ";
// it++;
// }
//
// cout << endl;
//}
//Iterator Begin()const
//{
// return Iterator(_head->_next);//也可以为return _head->_next 隐式类型转换
//}
//Iterator End() const
//{
// return Iterator(_head);
//}
/ /
void PrintList(const MyList<int>& l1)
{
MyList<int>::ConstIterator it = l1.Begin();//ConstIterator迭代器
while (it != l1.End())
{
//*it = 10;//本句会报错,因为是const迭代器 迭代器指向数据不能被改
cout << *it << " ";
it++;
}
cout << endl;
}
int main()
{
MyList<int>l1;
l1.PushBack(1);
l1.PushBack(3);
l1.PushBack(3);
l1.PushBack(4);
l1.PushBack(3);
PrintList(l1);
l1.Unique();
l1.Remove(3);
PrintList(l1);
l1.Reverse();
PrintList(l1);
MyList<int>::Iterator it = l1.Begin();
/*while (it != l1.End())//STL中删除存在迭代器失效 因此Erase删除必须用一个迭代器接收,返回的是下一个迭代器
{
if (*it % 2 == 0)
{
it=l1.Erase(it);
}
else
{
++it;
}
}*/
//while (it != l1.End())//如果我就想这样用,怎末办?怎样改进Erase
//{
// if (*it % 2 == 0)
// {
// l1.Erase(it);
// }
// ++it;
//}
//PrintList(l1);
/一个面试题 /
//Iterator Erase(Iterator& pos)//注意此处给的是引用,因为删除pos位置迭代器,此时pos位置(也就是it)已经被删除,如果继续++it就会迭代器失效
//{ //但是现在我们给pos赋值为前一个迭代器 ,加加指向后面便可解决这个问题
// assert((pos != End()) && (pos._node));
// Node* prev = pos._node->_prev;
// Node* next = pos._node->_next;
// delete pos._node;
// prev->_next = next;
// next->_prev = prev;
// pos = prev;
// return Iterator(next);//也可以是return next;隐式类型转换
//}
system("pause");
return 0;
}
上面自己实现的list,有一句MyList<int>::ConstIterator it = l1.Begin()没有自己合成拷贝构造,用自动生成的那个,浅拷贝。为什莫不出错。。
以前出错的原因是:多个指针指向一块空间析构时被析构了多次,而本次不会出错因为迭代器不用释放节点,迭代器不析构这个结点,析构结点是链表做的是。迭代器只负责访问,修改遍历(也就是要两个迭代器指向同一位置,才能修改),不释放。