如何使用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()没有自己合成拷贝构造,用自动生成的那个,浅拷贝。为什莫不出错。。
以前出错的原因是:多个指针指向一块空间析构时被析构了多次,而本次不会出错因为迭代器不用释放节点,迭代器不析构这个结点,析构结点是链表做的是。迭代器只负责访问,修改遍历(也就是要两个迭代器指向同一位置,才能修改),不释放。