建网站与建网页的区别,电子商务网站建设与管理期末答案,wordpress版型,卖货网站平台文章目录 初步认识①定义②底层原理③迭代器的分类 一、基本使用1.插入结点元素2.删除结点元素3.合并两个有序链表4.将一条链表的某一部分转移到另一条链表5.对链表排序并去重6.vector与list排序的比较 二、模拟实现①要点说明②基本框架③迭代器构造函数- -*-list里的迭代… 文章目录 初步认识①定义②底层原理③迭代器的分类 一、基本使用1.插入结点元素2.删除结点元素3.合并两个有序链表4.将一条链表的某一部分转移到另一条链表5.对链表排序并去重6.vector与list排序的比较 二、模拟实现①要点说明②基本框架③迭代器构造函数- -*-list里的迭代器 ④insert⑤erase⑥push_back⑦push_front⑧pop_front⑨pop_back()⑩构造函数⑪clear⑫析构函数⑬赋值重载 源码总结 初步认识 在正式讲解之前,我们先简单的认识一下list
①定义
template class T, class Alloc allocatorT class list;同样这里有两个模板参数第一个是实例化的类型第二个是空间配置器。
②底层原理
库里的list是采用带头双向循环链表进行实现的。
forward_list是单链表 带哨兵位的头结点是为了给end()迭代器留位置。
③迭代器的分类 1.输入迭代器 2.输出迭代器 3.单向迭代器——forward_list,unorder_xxx 4.双向迭代器——list/map/set 5.随机访问迭代器——vector/string/deque 之间的关系
从左到右是被包含的关系。 一、基本使用
1.插入结点元素 listint 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;listint::iterator it lt.begin();for (size_t i 0; i 5; i){it;}//在第五个位置的前面插入10//第五个位置——是下标为5也就是第六个元素。lt.insert(it,10);for (auto e : lt){cout e ;}cout endl;说明因为list不支持随机访问因此没有[] 运算符重载但支持- -。 这里的迭代器在插入之后并没有失效因为结点的插入是单个申请单个释放的。不存在 扩容的现象。
2.删除结点元素
void test_list()
{listint lt;lt.push_back(2);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(90);lt.push_back(6);lt.push_back(7);for (auto e : lt){cout e ;}cout endl;//删除所有的偶数结点listint::iterator it lt.begin();while (it ! lt.end()){if (*it % 2 0){it lt.erase(it);}else{it;}}for (auto e : lt){cout e ;}cout endl;}erase在释放之后迭代器是肯定失效的因为其所指向的空间都失效了。因此库里采用返回值进行更新迭代器。
3.合并两个有序链表
前提必须是有序的。
void test_list()
{listint lt;lt.push_back(2);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);lt.push_back(6);lt.push_back(7);for (auto e : lt){cout e ;}cout endl;listint lt1;lt1.push_back(1);lt1.push_back(3);lt1.push_back(5);lt1.push_back(7);lt1.push_back(9);for (auto e : lt1){cout e ;}cout endl;//将lt1合并到lt上lt.merge(lt1);for (auto e : lt){cout e ;}cout endl;}4.将一条链表的某一部分转移到另一条链表
接口 void splice (iterator position, list x);void splice (iterator position, list x, iterator i);void splice (iterator position, list x, iterator first, iterator last);注意迭代器/迭代器区间不能重合
listint lt;lt.push_back(2);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);lt.push_back(6);lt.push_back(7);for (auto e : lt){cout e ;}cout endl;listint lt1;lt1.push_back(1);lt1.push_back(3);lt1.push_back(5);lt1.push_back(7);lt1.push_back(9);for (auto e : lt1){cout e ;}cout endl;//将lt1转移到到lt的前面lt.splice(lt.begin(),lt1);for (auto e : lt){cout e ;}cout endl;//将lt的后半部分转移到lt1上listint::iterator it lt.begin();for (size_t i 0; i 5; i){it;}lt1.splice(lt1.begin(), lt ,it, lt.end());for (auto e : lt1){cout e ;}cout endl;//将lt1的第一个结点移到lt的最前面lt.splice(lt.begin(), lt1, lt1.begin());for (auto e : lt){cout e ;}cout endl;5.对链表排序并去重
unique去重的前提是有序。 listint lt;lt.push_back(2);lt.push_back(1);lt.push_back(3);lt.push_back(4);lt.push_back(2);lt.push_back(6);lt.push_back(4);lt.sort();for (auto e : lt){cout e ;}cout endl;lt.unique();for (auto e : lt){cout e ;}cout endl;6.vector与list排序的比较
void test_list2()
{listint lt;vectorint v;//设置随机数起点srand((unsigned)time(nullptr));size_t datas_num 1000000;for (size_t i 0; i datas_num; i){int n rand();lt.push_back(n);v.push_back(n);}int begin1 clock();sort(v.begin(), v.end());int end1 clock();cout vector: (end1 - begin1) endl;int begin2 clock();lt.sort();int end2 clock();cout list: (end2 - begin2) endl;
}结果list的排序有点挫不过如果数据量比较小可以使用list提供的排序数据量比较大的话那就将list的数据拷贝到vector进行排序再拷贝回去。注意在debug下进行测试可能会得到不一样的结果因为vector是使用递归的快排进行实现的如果debug下添加的调试信息会使栈帧的开销较大从而影响时间的效率。而list的底层原理是归并虽然也是递归但调试信息添加的可能较少因此会较快。而realease版本是发型版本是做了优化的性能更好。
二、模拟实现
①要点说明
1.为了不与库里面的list冲突我们需要命名空间对自己实现的类进行封装2.这里我们实现的框架是按照带头双向循环链表的数据结构进行实现的。3.为了理解下面的接口是分开讲解的最后我会给出源码。
②基本框架
templateclass T
struct list_node
{list_node(const T val T()):_val(val),_next(nullptr),_prev(nullptr){}T _val;list_node* _next;list_node* _prev;
};templateclass T
class list
{typedef list_nodeT Node;
public:private:Node* _head;size_t _size;
};③迭代器
这是list的最关键的部分
我们先来谈谈是如何实现的迭代器必然是指向一个结点的指针但是能完成操作以及解引用操作那该怎么办呢答案其实很简单——用类进行封装通过运算符重载实现相应的功能。
简单的迭代器框架
templateclass T
struct list_iterator
{typedef list_iteratorT iterator; Node* _node;
};构造函数
list_iterator(Node* val nullptr):_node(val)
{}
list_iterator(const iterator lt):_node(lt._node)
{}析构我们使用默认生成的即可可千万不要写析构释放迭代器指向的空间因为迭代器指向的空间属于list。应由list进行管理。
剩下的操作是类里面进行重载-- ,*。 //前置
iterator operator ()
{_node _node-_next;return *this;
}
//后置
iterator operator (int)
{list_iterator tmp(_node);_node _node-_next;return tmp;
}- -
//前置
iterator operator --()
{_node _node-_prev;return *this;
}
//后置
iterator operator --(int)
{list_iterator tmp(_node);_node _node-_prev;return tmp;
}*
T operator *()
{return _node-_val;
}这样迭代器的基本功能就实现了但是const的迭代器该如何实现呢
是这样么
typedef const list_iteratorT const_iterator;这样迭代器的成员变量不可被修改即不可以或者- -不符合要求我们想要的只是返回的值不可被修改。
一般都会再拷贝一份进行将拷贝的迭代器改改但是我们还可以设置第二个模板参数这样外面可以这样定义。
templateclass Tclass Ref struct list_iterator;
//里面的运算符重载——*
Ref operator *()
{return _node-_val;
}//list里面可以这样定义typedef list_iteratorT,const T const_iterator;
typedef list_iteratorT,T iterator;这样问题就解决了。
-
还有第二个问题如果迭代器指向的是自定义类型比如
struct A
{A(int x 0):_a1(x){}int _a1;
};如果想要访问其成员直接解引用是不行的。
我们可以这样
iterator it lt.begin();
(*it)._a1;访问其元素。
我们还可以重载- 进行访问:
T* operator -()
{return (_node-_val);
}
iterator it lt.begin();
it-_a1;这样其实省略了一个箭头这省略的一个箭头其实是为了美观编译器在处理时会自动加上的。
如果是const对象呢其实处理方式一样的再加一个模板参数。
更新后的模板和迭代器:
templateclass T,class Ref,class Ptr struct list_iterator;
Ptr operator -()
{return (_node-_val);
}
typedef list_iteratorT,const T,const T* const_iterator;
typedef list_iteratorT,T,T* iterator;那完整版的迭代器即为:
templateclass T,class Ref,class Ptr
struct list_iterator
{typedef list_nodeT Node;typedef list_iteratorT, Ref, Ptr self;typedef list_iteratorT, T, T* iterator;list_iterator(Node* val nullptr):_node(val){}list_iterator(const iterator lt):_node(lt._node){}//重载self operator () {_node _node-_next;return *this;}//后置为了区别需要重载一下这里的参数实际上没啥用self operator (int){list_iterator tmp(_node);_node _node-_next;return tmp;}self operator --(){_node _node-_prev;return *this;}self operator --(int){list_iterator tmp(_node);_node _node-_prev;return tmp;}bool operator ! (const self it) const{return _node ! it._node;}bool operator (const self it) const//const和非const都能用{return _node it._node;} Ptr operator -(){return (_node-_val);}Ref operator *(){return _node-_val;}Node* _node;
};list里的迭代器
iterator begin()
{return _head-_next; //隐式类型转换
}
const_iterator begin()const
{return _head-_next;}
iterator end()
{return _head;
}
const_iterator end()const
{return _head;
}④insert
//在pos之前插入
void insert(iterator pos, const T val)
{Node* newnode new Node(val);Node* cur pos._node;Node* prev cur-_prev;newnode-_next cur;newnode-_prev prev;cur-_prev newnode;prev-_next newnode;_size;
}⑤erase
Node* erase(iterator pos)
{assert(pos ! end());//这个检查是不很严格的如果删除一个未知的结点这个是检查不到的!Node* cur pos._node;Node* prev cur-_prev;Node* next cur-_next;prev-_next next;next-_prev prev;delete cur;_size--;return next;
}⑥push_back
void push_back(const T val)
{//Node* tail _head-_prev;//Node* newnode new Node(val);//newnode-_next _head;//newnode-_prev tail;//_head-_prev newnode;//tail-_next newnode;insert(end(), val);
}⑦push_front
void push_front(const T val)
{insert(begin(), val);
}⑧pop_front
void pop_front()
{erase(begin());
}⑨pop_back()
void pop_back()
{erase(--end());
}⑩构造函数
//默认构造函数
list()
{_head new Node;_head-_next _head;_head-_prev _head;_size 0;
}//拷贝构造
list(const listT lt)
{_head new Node;_head-_next _head;_head-_prev _head;_size 0;for (auto e : lt){push_back(e);}
}⑪clear
void clear()
{iterator it begin();while (it ! end()){it erase(it);}
}⑫析构函数
~list()
{clear();delete _head;
}⑬赋值重载
void swap(list tmp)
{std::swap(_head, tmp._head);std::swap(_size, tmp._size);
}
list operator (list tmp)
{swap(tmp);return *this;
}剩余的接口过于简单这里就不再列出了有兴趣请看源码。
源码
namespace my_list
{templateclass Tstruct list_node{list_node(const T val T()):_val(val),_next(nullptr),_prev(nullptr){}T _val;list_node* _next;list_node* _prev;};templateclass T,class Ref,class Ptrstruct list_iterator{typedef list_nodeT Node;typedef list_iteratorT, Ref, Ptr self;typedef list_iteratorT, T, T* iterator;list_iterator(Node* val nullptr):_node(val){}list_iterator(const iterator lt):_node(lt._node){}//重载self operator () {_node _node-_next;return *this;}//后置为了区别需要重载一下这里的参数实际上没啥用self operator (int){list_iterator tmp(_node);_node _node-_next;return tmp;}self operator --(){_node _node-_prev;return *this;}self operator --(int){list_iterator tmp(_node);_node _node-_prev;return tmp;}bool operator ! (const self it) const{return _node ! it._node;}bool operator (const self it) const//const和非const都能用{return _node it._node;} Ptr operator -(){return (_node-_val);}Ref operator *(){return _node-_val;}Node* _node;};templateclass Tclass list{typedef list_nodeT Node;public:typedef list_iteratorT,T,T* iterator;typedef list_iteratorT,const T,const T* const_iterator;list(){_head new Node;_head-_next _head;_head-_prev _head;_size 0;}list(const listT lt){_head new Node;_head-_next _head;_head-_prev _head;_size 0;for (auto e : lt){push_back(e);}}~list(){clear();delete _head;}void clear(){iterator it begin();while (it ! end()){it erase(it);}//cout _size endl;}iterator begin() {//return _head-_next;//隐式类型转换为list_itertorreturn _head-_next; }const_iterator begin()const{//return _head-_next;//隐式类型转换为list_itertorreturn _head-_next;}iterator end(){return _head;//返回的是_head的拷贝因此返回对象具有常属性//隐式类型转换为list_itertor//return itrator(_head-next); //匿名对象}const_iterator end()const{return _head;//返回的是_head的拷贝因此返回对象具有常属性//隐式类型转换为list_itertor//return itrator(_head-next); //匿名对象}void push_back(const T val){//Node* tail _head-_prev;//Node* newnode new Node(val);//newnode-_next _head;//newnode-_prev tail;//_head-_prev newnode;//tail-_next newnode;insert(end(), val);}//在pos之前插入void insert(iterator pos, const T val){Node* newnode new Node(val);Node* cur pos._node;Node* prev cur-_prev;newnode-_next cur;newnode-_prev prev;cur-_prev newnode;prev-_next newnode;_size;}Node* erase(iterator pos){assert(pos ! end());//这个检查是不很严格的如果删除一个未知的结点这个是会报错的!Node* cur pos._node;Node* prev cur-_prev;Node* next cur-_next;prev-_next next;next-_prev prev;delete cur;_size--;return next;}void pop_back(){erase(--end());}void pop_front(){erase(begin());}void push_front(const T val){insert(begin(), val);}size_t size(){return _size;}bool empty(){return _size 0;}void swap(list tmp){std::swap(_head, tmp._head);std::swap(_size, tmp._size);}list operator (list tmp){swap(tmp);return *this;}private:Node* _head;size_t _size;};
}总结 今天的分享就到这里了如果觉得文章不错点个赞鼓励一下吧我们下篇文章再见