当前位置: 首页 > news >正文

北海网站设计网络服务提供者知道或者应当知道

北海网站设计,网络服务提供者知道或者应当知道,wordpress tag 搜索,网络建站1. list的介绍及使用list和之前容器介绍的一样,第二个参数是内存池,它的底层是一个带头双向循环链表。它的使用很便捷,来看看构造:有无参的、用n个val、迭代器区间、拷贝构造,发现和之前学过的容器的用法很相似。list的…

1. list的介绍及使用

    list和之前容器介绍的一样,第二个参数是内存池,它的底层是一个带头双向循环链表。它的使用很便捷,来看看构造:

有无参的、用n个val、迭代器区间、拷贝构造,发现和之前学过的容器的用法很相似。list的接口中没有resize、reserve这样的说法,因为它不涉及扩容了,不用提前开空间。list里面也提供了一些新的接口:

下面来简单使用一下list:

这里遍历不能用下标加方括号,因为不是连续的空间了,所以迭代器才是通用玩法。再看看insert,从string以后insert都变了,string部分是以下标去插入,现在不是下标,都给的是迭代器:

但它和vector还是有些差别的,比如想从第5个位置插入数据,如果是vector应该是这样写:v.insert(v.begin()+5,10),如果是list不能lt.insert(it.begin()+5,10)这样写。因为vector是连续的物理空间,可以通过加加到第5个位置,但它插入时的代价大,需要把数据都挪走;list物理空间不是连续的,虽然要想实现也可以支持,但代价太大了。list想要再第5个位置插入值可以这样写:

再如list想从3前面插入30,但不知道3在哪个位置,所以可以想到用find,但list没提供find,因为stl有两大组件,容器和算法,外部通常不能访问容器数据,因为是私有的,stl就通过迭代器把它们联合起来,这样公共的一些算法可以提取出来。迭代器没有暴露容器底部细节:

通过统一的方式访问容器,不需要关注底层实现。所以迭代器是优秀的设计,还有个细节是不是it<end而是!=,因为对不连续的空间没法用小于参考。因此算法写了通用的可以用算法中的:

可以在给的迭代器区间查val,算法中只要满足迭代器不管底层怎样都是支持的,而且迭代器设计是左闭右开,找不到返回last。下面体验一下:

那链表的insert有没有迭代器失效问题?没有,因为链表没有扩容野指针问题,也没有挪数据位置意义改变的问题。那erase有吗?

erase可以删除某个位置,删除一段区间。erase肯定有迭代器失效的问题,因为结点都没有了。那如果erase要持续的删除呢?通过接收返回值,返回值指向被删除元素的下一个位置(比如删偶数):

swap就是两个链表直接换,clear就是把结点都清了。链表的相关操作中单独针对性的提供了一些操作,有reverse,但这个接口库中也有,感觉实现了没有意义,反正逻辑实现是一样的:

再来看看sort,库中也有sort,用一下:

但编译的时候发现sort编译报错了:

跳转过去发现底层是ULast-UFirst,底层是快排,链表没法适应该场景。再单独看不同的算法,如上图的sort和reverse,发现模板参数名那有些差异。为什么呢?其实迭代器从功能角度讲是会分类的,分为单向、双向、随机迭代器。单向只能++,双向可以++/--,随机是可以++/--/+/-。如单链表是单向迭代器,双向链表是双向迭代器,vector、string是随机迭代器:

也意味着参数名字暗示了你适合用哪一个算法,如Bid适合用双向,Input适合用单向,Rand适合用随机。之前我们说的正向、反向迭代器是从遍历功能的角度来说,这里是从性质划分,和容器的底层结构有关。因为sort是随机迭代器,所以list调用的时候报错了。因此能否用一个算法要看容器的迭代器到底是哪一种,那我怎么知道是哪一种?文档中其实有说明迭代器类型是哪一种:

如list的迭代器是双向迭代器。它这不是完全按名字匹配的,(随机迭代器可以认为是一个特殊的双向迭代器)随机迭代器满足双向迭代器的性质,所以看到算法中的迭代器是InPut说明单向、双向、随机迭代器都可以用;看到Bid说明双向、随机迭代器可以用:

是上图这样的一种使用关系。所以链表这里写的sort算法是有意义的,但也可以认为除了方便外意义不是很大,因为实际中其实不用list排序,vector效率远高于list:

首先弄个伪随机数方便生成随机数,定义了vector(提前开好空间)和list,然后再两容器中插入相同的数据,对比它们的排序差异,vector用算法sort,链表用自己的sort,可以看到差距很大,list慢一些。再换一种方式,比如排list的数据,现在把list拷贝到vector,然后用vector排序,排完再拷贝回list:

发现list还是慢一些,所以从效率角度看list的sort意义不大。下面继续看,merge就是两个链表可直接进行归并,归并排序的前提是有序,先sort再merge:

unique是唯一的意思,它的本质是去重,去重的前提也是要排序:

因为不排序去重效率非常低。remove就是find+erase,remove这如果这个值不存在:

发现什么事都不干。还有splice,它是结合的意思,功能是把一个链表的内容转移到另外一个(把A链表的结点取下来直接接入到B链表):

接口(1)是把x链表转移到当前链表这个迭代器位置之前;(2)是把x链表的i位置的值转移到当前链表这个位置之前;(3)是把x链表的一部分转移到当前链表这个位置之前。

2. list的模拟实现

    下面来进行list的模拟实现,实现前先看一下源代码,这里就大概看一下:

这是链表结点结构,可以看出是一个双向链表(奇怪的是这是void*,不是结点类型指针)。下面看看链表的成员变量:

库中有个特点是很喜欢typedef,找不到可以右击速览定义(转到定义:跳到定义的地方):

可以看到它是一个list_node*,list_node也被typedef过。假设现在不知道list是带头双向循环链表:首先看到有个结点,然后看构造:

无参的构造函数初始化了一个结点,结点的next指向自己,prev指向自己,再速览一下get_node:

看到结果是空间配置器来的,释放结点调的是put_node.头插尾插调的是inster:

现在上手,首先定义一个list_node,这里用struct定义,如果用class里面要用public(因为结点不弄成公有一会很麻烦,除非弄各种友元)。在前面试用链表时我们也没有触碰到结点,所以结点公有时对别人也是隐藏的。下面实现一下:

在定义链表时,先typedef一下,因为类模板中类名不是类型,防止写错,然后写好成员变量:

下面快速写一个出现先用一用,先写个构造,new个结点,prev和next指向自己:

下面再来写push_back,该结构中找到尾就可以插入,tail是head的前一个,然后建立结点连接就可以了:

然后再补充一个构造函数:

这样一个浅浅的链表就出来了。下面就来搭建迭代器:

能不能像之前实现一样,直接Node*充当迭代器?不可以:

因为未来begin给it,it解引用不能得到想要的数据,它解引用后是个结点,并且it++后也不能到下一个位置,因为它不连续。此时运算符重载就要起作用了,再上手一个自定义类型来配合。因为用的时候是这样用:

根据用法结合来写。iterator是类里面typedef的,那迭代器是如何构造出来的?迭代器是一个自定义类型,这个自定义类型成员是一个结点的指针:

我本来也想用结点指针做迭代器,但无奈的是,不能像vector原生指针那样,因为底层结构有差异,但结构指针确实可帮我找到下一个,也可帮我取数据,内置类型不符合我们行为。因此C++可以用类去封装内置类型,然后重载运算符,此时就可以控制它的行为了。外部*it就是调用operator*,++就是调用operator++,运算符重载就变成我们来控制了,这样实现后用起来和之前感觉一样,但实际底层不一样。现在来完成,先实现begin和end:

(1.单参数构造函数支持隐式类型转换 2.返回对象)上图两种本质是一样的,都生成了匿名对象。然后实现解引用,*it去调operator*期望返回值,因为出了作用域结点还在,用引用返回可读可写:

再重载一个++,迭代器++返回的还是迭代器,然后走到node的next就可以:

再重载一个!=,用结点指针来进行相关比较:

下面测试一下:

发现!=有报错,因为end那里是传值返回,返回head的拷贝,是临时对象,具有常性,所以加const就没有问题了:

有了迭代器后范围for也就支持了,库也是直接替换:

看一下下图:

这里还发生了一件事情,这里调begin,通过拷贝构造把值给it,迭代器里目前没有写拷贝构造,默认生成的拷贝构造对内置类型完成浅拷贝,一个指针在这浅拷贝没啥问题。但多个对象指向同一结点为啥没有因多次析构崩溃?因为这个结点不属于迭代器,只是借助结点访问,不管释放什么的,链表里会释放。下面再看后置++,返回++之前的值;还有==,一起补充上:

这样迭代器就基本上完善了。下一个话题是如何设计const迭代器,可以这样设计const迭代器吗?

不可以,迭代器模拟的是指针的行为,指针有两种const指针,一种是const T* ptr1,一种是T* const ptr2,const迭代器是模拟ptr1的行为。如果按照上图那样设计模拟的是ptr2,因为这样设计是迭代器本身不能被修改,也就不可以++修改,我们的目的是让指向的内容不能修改。那如何控制指向数据不能修改?控制返回类型就可以了:

此时有(*it) += 1就会跑不过,因为解引用之后返回的是const对象。按一般的思路我们把类再拷贝一份,这个新类几乎所有的功能和原来是一样的,唯独有些返回值不一样,把__list_iterator的地方改为__list_const_iterator,然后list中再typedef为const_iterator,但这样设计太冗余了,怎么改进?这两个类只是有些接口上返回值不一样,可以通过一个类型去控制返回值就可以。那怎么控制返回值呢?可以去增加模板参数叫Ref:

operator*的返回值是Ref:

从类模板来说Ref是什么并不知道,对普通的iterator它是T引用,对const_iterator来说它是const T引用:

像下图:

返回这都用的类模板,加了模板参数后它们都要跟着改,所以typedef一下,避免又加模板参数后跟着都改:

有些地方喜欢定义成self,然后把__list_iterator<T>改为self。

上图看到,源码中还重载了一个->运算符,并且是三个模板参数。operator->的返回值是pointer,pointer就是模板参数,结果返回数据取地址。operator->有一点我们是可以理解的:指针除了有*解引用还有->解引用,->相比*而言,*是取指针指向的数据,如果是结构体指针就要用->,迭代器模拟指针的行为,什么时候模拟结构体指针呢?

默认返回T*。现在比如有A这样的类:

然后构造一些对象进去:

现在想对自定义类型进行访问:

给*it无法跑,因为*it是取里面的数据,里面的数据是A,A是自定义类型,自定义类型想走也可以,在A中重载流插入。那有没有其它方式可以访问?

可以像上图这样。但这里迭代器模拟的是一个指向结构的指针,要用箭头,所以可以这样写:

但这里有些古怪的地方:(*it)._a1中*it先转化为it.operator*(),返回的是一个A&,然后对象._a1是没啥问题的;it->a1中it->转化为it.operator->(),它的返回值是A*,A*直接跟_a1访问不了,这严格来说正确写法应该是it->->_a1才符合语法,因为运算符重载要求可读性,这可以认为编译器特殊处理省略了一个->。如果是const迭代器,operator->这应该是返回const T*,所以还是多加一个模板参数Ptr:

普通迭代器传T*,const迭代器传const T*,用Ptr代替operator->的T*(==和!=不修改成员函数+const):

链表的核心部分结束,下面完善一下链表:首先看insert,这里不用对pos检查,因为没有说不允许在哪个位置之前插入(反而erase需要检查pos!=end() )。定义cur为pos.node(要插入的结点)(也可以理解为啥迭代器设置为struct,因为全公有,私有还要友元一下),再找前一个位置,再弄一个新节点,然后改变三结点的链接:

删除也是找当前位置的结点,找到前一个与后一个,改变连接关系,删除结点。这里有迭代器失效的问题,因为pos指向的结点被我们释放了,所以返回下一个位置的迭代器(insert在库中返回的是新插入元素的位置):

尾插就是在哨兵位的前面插入,头插就是在第一个位置前面插入:

尾删就是删除end的前一个,顺便实现一下--,头删删除begin位置就可以:

还有个size,遍历计数:

但是如果比喜欢O(N)遍历,可以增加一个size成员,这样就直接return size,前面每次更新一下。clear要清除数据,但不清哨兵位(erase后不能++,所以接收返回值)(若用记录size的方法记得清零):

析构就是先clear,在deleete哨兵位:

现在还剩拷贝构造,拷贝构造也面临深浅拷贝的问题,先拷贝试一下:

运行崩了,原因肯定是析构两次。调式看到报错的地方在erase,实际不一定在这里,调试窗口有个调用堆栈,可看到调用的函数:

main函数调了Test_list3,list3调析构,析构调clear,clear调erase然后崩了。现在完成拷贝构造,首先把初始化做了(比如lt1拷贝构造lt2,lt2的哨兵位头结点好得要出来),然后遍历调push_back:

这里还可以优化一下,构造和拷贝构造初始化那里有些重复,所以有时候会写个empty_init,然后重复的地方复用就行:

下面写赋值,可用传统写法,这里用现代写法来写,拷贝构造出我想要的,然后一交换,顺便完善交换函数:

下面简单测试一下:

还有一个点,库里的赋值和我们写的有些不一样:

我们返回写的是类型,它写的是类名,对拷贝构造和赋值那块写类名也可以,语法上可识别,但不推荐这样写,降低了可读性。可以认为这里是特例,类模板在类里面写类名和类型都是可以的。

3.相关代码

//list.h#pragma oncenamespace yxx
{template<class T>struct list_node{list_node(const T& val = T()):_next(nullptr),_prev(nullptr),_val(val){}list_node<T>* _next;list_node<T>* _prev;T _val;};template<class T, class Ref, class Ptr>struct __list_iterator{typedef list_node<T> Node;typedef __list_iterator<T, Ref, Ptr> self;Node* _node;__list_iterator(Node* node):_node(node){}Ref& operator*(){return _node->_val;}Ptr 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->_perv;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& it)const{return _node != it._node;}bool operator==(const self& it)const{return _node == it._node;}};template<class T>class list{typedef list_node<T> Node;public:typedef __list_iterator<T, T&, T*> iterator;typedef __list_iterator<T, const T&, const T*> const_iterator;//typedef const __list_iterator<T> const_iterator  erroriterator begin(){//return _head->nextreturn iterator(_head->_next);}iterator end(){return _head;//return iterator(_head);}const_iterator begin() const{//return _head->_next;return const_iterator(_head->_next);}const_iterator end() const{return _head;//return const_iterator(_head);}void empty_init(){_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;}list(){empty_init();/*_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;*/}//void push_back(const T& x )//{//	Node* tail = _head->_prev;//	Node* newnode = new Node(x);//	tail->_next = newnode;//	newnode->_prev = tail;//	newnode->_next = _head;//	_head->_prev = newnode;//}void swap(list<T>& lt){std::swap(_head, lt._head);std::swap(_size, lt._size);}list<T>& operator=(list<T> lt){swap(lt);return *this;}~list(){clear();delete _head;_head = nullptr;}void clear(){iterator it = begin();while (it != end()){it = erase(it);}_size = 0;}list(const list<T>& lt){/*_head = new Node;_head->_prev = _head;_head->_next = _head;_size = 0;*/empty_init();for (auto& e : lt){push_back(e);}}void push_back(const T& x){insert(end(), x);}void push_front(const T& x){insert(begin(), x);}iterator insert(iterator pos, const T& x){Node* cur = pos._node;Node* prev = cur->_prev;Node* newnode = new Node(x);prev->_next = newnode;newnode->_next = cur;cur->_prev = newnode;newnode->_prev = prev;++_size;return newnode;}void pop_back(){erase(--end());}void pop_front(){erase(begin());}iterator 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;}size_t size(){return _size;}/*	size_t size(){size_t sz = 0;iterator it = begin();while (it != end()){++sz;++it;}return sz;}*/private:Node* _head;size_t _size;};class A{public:A(int a1 = 0, int a2 = 0):_a1(a1),_a2(a2){}int _a1;int _a2;};void Test_list1(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int>::iterator it = lt.begin();while (it != lt.end()){cout << *it << ' ';++it;}cout << endl;for (auto e : lt){cout << e << " ";}cout << endl;}void Test_list2(){list<A> lt;lt.push_back(A(1, 1));lt.push_back(A(2, 2));lt.push_back(A(3, 3));lt.push_back(A(4, 4));list<A>::iterator it = lt.begin();while (it != lt.end()){/*	cout << (*it)._a1 << " "; cout << (*it)._a2 << " ";*/cout << it->_a1 << " " << it->_a2 << endl;++it;}cout << endl;}void Test_list3(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);list<int> lt1(lt);for (auto e : lt1){cout << e << " ";}}void Test_list4(){list<int> lt;lt.push_back(1);lt.push_back(2);lt.push_back(3);lt.push_back(4);for (auto e : lt){cout << e << " ";}cout << endl;list<int> lt1;lt1.push_back(5);lt1.push_back(6);lt1.push_back(7);lt1.push_back(8);for (auto e : lt1){cout << e << " ";}cout << endl;lt1 = lt;for (auto e : lt1){cout << e << " ";}}
}
//Test.cpp#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include <stdbool.h>
#include <assert.h>
using namespace std;#include "list.h"int main()
{yxx::Test_list4();return 0;
}

http://www.dtcms.com/a/514930.html

相关文章:

  • 河北建设厅查询网站首页杭州百度快照优化排名
  • 哪些网站需要做分享按钮腾讯云wordpress密码
  • 福州有网站建设的公司排名西安专业的网站开发公司
  • 定制型网站建设合同范本足球比赛直播现场在线观看
  • 用asp.net做网站计数器什么是软件的开发平台
  • 网站开发都有哪些语言电商设计网站
  • 如何优化网站内容网页设计的目的是指设计者
  • 电商网站seo优化目标分解葫芦岛高端网站制作
  • 附近网站电脑培训班网站团购功能怎么做
  • 运城手机网站建设百度云超级会员试用1天
  • 网站后台页面企石镇网站建设
  • 做资源网站赚钱吗wordpress十大主题
  • 台州网站seo外包网站后台首页
  • 永泰县住房和城乡建设局网站网站建站平台公司
  • 政务中心建设网站seo软件开发
  • wordpress站点添加skype门户网站和微网站的区别
  • 淘宝单网站建设赣州网站优化公司
  • 网站安全如何做网站推广优化哪家公司好
  • 如何做企业网站推广产品网络营销推广方案分析
  • 陕西省建设信息网站ppt精美模板
  • 公司设计网站有哪些新站秒收录接口
  • 第一ppt网课件下载北京百度推广seo
  • 中国建设人才信息网站鲜花网站建设文档
  • 企业网站主页模板wordpress批量删除字段
  • 哪个网站有律师做的案件响应式布局
  • 中国建设工程造价管理系统网站温州建筑信息平台
  • 厦门在线制作网站网站空间单位
  • 李鸿星电子商务网站建设免费申请激活码
  • 怎样说服客户做网站seo标题是什么
  • 网站怎么做关键词库企业咨询顾问服务协议