1.迭代器的功能以及性质
功能有iterator,reverse_iterator,const_iterator,const_reverse_iterator
性质有单向,双向和随机,单向的迭代器只能++操作,双向只能++/--俩种,随机则可以执行++/--/+/-的操作
底层结构可以决定使用那些算法,下图的关系可知output的操作是包括随机,最后一个可以包容前面的,InputIterator表示哪一个都可以接受,单向,双向及随机都可以作为参数。
2.list的构造
list构造函数是调用了一个函数,名字上可以理解是空的初始化,内容是调用函数获得一个节点,把下一个指向自己,前一个也指向自己,就是一个哨兵位。
3.push_back实现
这里head是哨兵位,则begin就是head的下一个,end就是head的前一个(或者可以把有哨兵位的链表环型的),要插入新的节点就把之前tail的下一个指向新的,然后新的节点的下一个指向哨兵位,在把prev(前一个指针)连接,就完成了。
void push_back(const T& x)
{Node* newnode = new Node(x);Node* tail = _head->_prev;tail->_next = newnode;newnode->_prev = tail;newnode->_next = _head;_head->_prev = newnode;}
3.构造关于节点的模板
成员有节点的值,以及节点的前后指针,这里走list_node的构造,如果没有参数这个data会用匿名对象的data来拷贝给data,而匿名对象的data为0.
template<class T>struct list_node{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T& data = T()):_data(data), _next(nullptr), _prev(nullptr){}};void test_list1()
{list_node<int> x;/*list<int> It;It.push_back(1);It.push_back(2);It.push_back(3);It.push_back(4);list<int>::iterator it = It.begin();while (it != It.end()){cout << *it << " ";++it;}cout << endl;*/
}
4.list迭代器 list_iterator模板
在代码里有三个模版,第一个模板是关于节点的内容,节点的值,前后指针,第二个模板是指向节点的指针,可以通过这个去找到对应节点的位置,第三个模板是list的操作模板就是增删查改等操作的地方。
这个模板类的成员是Node* _node就是一个指向节点的指针,后面的operator就是移动指针和解引用指针以及布尔判断。
template<class T>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T> Self;Node* _node;list_iterator(Node* node):_node(node){}T& operator*(){return _node->_data;}Self& operator++(){_node = _node->_next;return *this;}Self& operator--(){_node = _node->_prev;return *this;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};
5.list模板
list的成员有Node* _head和size_t _size俩个,一个是指向节点的指针,另一个是链表的大小。
1.list构造
_head指向一个刚开辟的空间,然后把next和prev都指向自己,链表大小为0,
list()
{_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;
}
2.begin()和end()
哨兵位的下一个就是第一个节点,哨兵位的上一个就是最后一个节点,切记end()是指哨兵位的位置,begin()是哨兵位的下一个。
iterator begin(){return _head->_next;}iterator end(){return _head;}
3.insert
在指定位置前一个位插入节点,cur来保存指定位置的节点,prev保存指定位置的前一个节点,用要插入节点的值构造节点,把构造节点的下一个位置连到指定位置的节点,构造的新节点前一个节点指向指定位置的前一个节点,然后把指定位置的前一个节点的next于新节点连接,最后把size加一。
void insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;prev->_next = newnode;++_size;}
4.push_back和push_front
有了之前的insert,尾插就只用在哨兵位的前一个插入(哨兵位的前一个就是最后一个节点),头插就只用在哨兵位的下一个插入就可以。
void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}
5.erase
删除指定位置的节点,先保存要删除节点的俩个指针,指向前一个的和指向下一个的,然后把指向前一个节点连接到指向下一个节点,最后把指定位置节点pos删除,最后把size--。
void erase(iterator pos){assert(pos != end());Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->prev = prev;delete pos._node;--_size;}
6.pop_back和pop_front
有了之前的erase,尾删就是end()哨兵位的上一个删除,头删就是begin()哨兵位的下一个。
void pop_back(){erase(--end());}void pop_front(){erase(begin());}
7.size
链表的大小在插入或者删除时会变,判空用重载==与0相比。
size_t size() const{return _size;}bool empty() const{return _size == 0;}
6.splice函数
void splice(iterator pos, list& x);
第一个参数为指定list的一个位置,往里面插入里一个list,这里插入后,另一个链表的值就会空。
// 一个链表节点转移给另一个链表
std::list<int> mylist1, mylist2;
std::list<int>::iterator it;// set some initial values:
for (int i = 1; i <= 4; ++i)mylist1.push_back(i); // mylist1: 1 2 3 4for (int i = 1; i <= 3; ++i)mylist2.push_back(i * 10); // mylist2: 10 20 30it = mylist1.begin();
++it; // points to 2mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4
for (auto e : mylist1){cout << e << " ";}cout << endl;
void splice(iterator position, list& x, iterator i); 1
void splice(iterator position, list& x, iterator first, iterator last); 2
1函数第一个参数是需要一个指向原链表的位置,第二个参数是要插入的链表,第三个是要插入链表的第i个位置的元素。
2是把区间的元素给放到指定的位置,1是单个,2是划定一个区间,把区间的元素都移到指定位置,这里输入2则it就是指向lt的2的位置, 则区间为lt的2到lt的end(),也就是把2后面的所有都放到1的前面。(往前插入)
std::list<int>::iterator it;list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);lt.push_back(6);for (auto e : lt){cout << e << " ";}cout << endl;int x = 0;cin >> x;it = find(lt.begin(), lt.end(), x);if (it != lt.end()){//lt.splice(lt.begin(), lt, it);lt.splice(lt.begin(), lt, it, lt.end());}for (auto e : lt){cout << e << " ";}cout << endl;
}
7.总代码
test.cpp
#include"list.h"#include<iostream>
#include<algorithm>
#include<list>
#include<vector>
using namespace std;void test_op2()
{srand(time(0));const int N = 1000000;list<int> lt1;list<int> lt2;for (int i = 0; i < N; ++i){auto e = rand() + i;lt1.push_back(e);lt2.push_back(e);}int begin1 = clock();// 拷贝vectorvector<int> v(lt2.begin(), lt2.end());// 排序sort(v.begin(), v.end());// 拷贝回lt2lt2.assign(v.begin(), v.end());int end1 = clock();int begin2 = clock();lt1.sort();int end2 = clock();printf("list copy vector sort copy list sort:%d\n", end1 - begin1);printf("list sort:%d\n", end2 - begin2);
}void test_list6()
{// 一个链表节点转移给另一个链表std::list<int> mylist1, mylist2;std::list<int>::iterator it;// set some initial values:for (int i = 1; i <= 4; ++i)mylist1.push_back(i); // mylist1: 1 2 3 4for (int i = 1; i <= 3; ++i)mylist2.push_back(i * 10); // mylist2: 10 20 30it = mylist1.begin();++it; // points to 2mylist1.splice(it, mylist2); // mylist1: 1 10 20 30 2 3 4// mylist2 (empty)// "it" still points to 2 (the 5th element// 调整当前链表节点的顺序list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);lt.push_back(6);for (auto e : lt){cout << e << " ";}cout << endl;int x = 0;cin >> x;it = find(lt.begin(), lt.end(), x);if (it != lt.end()){//lt.splice(lt.begin(), lt, it);lt.splice(lt.begin(), lt, it, lt.end());}for (auto e : lt){cout << e << " ";}cout << endl;
}
int main()
{//test_list6();//test_op2();zym::test_list1();return 0;
}
#include"list.h"int main()
{//test_list6();//test_op2();zym::test_list1();return 0;
}
list.h
#pragma once#include<iostream>
using namespace std;namespace zym
{template<class T>struct list_node{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T& data = T()):_data(data), _next(nullptr), _prev(nullptr){}};template<class T>struct list_iterator{typedef list_node<T> Node;typedef list_iterator<T> Self;Node* _node;list_iterator(Node* node):_node(node){}T& operator*(){return _node->_data;}Self& operator++(){_node = _node->_next;return *this;}Self& operator--(){_node = _node->_prev;return *this;}bool operator!=(const Self& s) const{return _node != s._node;}bool operator==(const Self& s) const{return _node == s._node;}};template<class T>class list{typedef list_node<T> Node;public:typedef list_iterator<T> iterator;iterator begin(){return _head->_next;}iterator end(){return _head;}list(){_head = new Node;_head->_next = _head;_head->_prev = _head;_size = 0;}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;prev->_next = newnode;++_size;}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void erase(iterator pos){assert(pos != end());Node* prev = pos._node->_prev;Node* next = pos._node->_next;prev->_next = next;next->prev = prev;delete pos._node;--_size;}size_t size() const{return _size;}bool empty() const{return _size == 0;}private:Node* _head;size_t _size;};void test_list1(){list<int> It;It.push_back(1);It.push_back(2);It.push_back(3);It.push_back(4);list<int>::iterator it = It.begin();while (it != It.end()){cout << *it << " ";++it;}cout << endl;}
}