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

手机网站自助建设友情链接源码

手机网站自助建设,友情链接源码,大连做网站的网络公司,公司 网站源码这里写目录标题vector和stirng的细节对于stringlist的使用list的迭代器反向迭代器构造函数关于list::sort的排序uniquelist的底层模拟实现结点类的实现迭代器模拟实现list实现插入的实现迭代器失效inserterase析构函数拷贝构造赋值构造函数vector和stirng的细节 复习vector的深…

这里写目录标题

  • vector和stirng的细节
    • 对于string
  • list的使用
    • list的迭代器
    • 反向迭代器
    • 构造函数
    • 关于list::sort的排序
    • unique
  • list的底层模拟实现
    • 结点类的实现
    • 迭代器模拟实现
    • list实现
  • 插入的实现
  • 迭代器失效
    • insert
    • erase
  • 析构函数
  • 拷贝构造
  • 赋值构造函数

vector和stirng的细节

复习vector的深浅拷贝。

下图是vector<vector< int>> 的底层模型
在这里插入图片描述实际和动态二维数组的图一样。

vv[i][j] 表示什么意思?
vv[ i]表示访问第几个vector,
vv[i][ j]表示访问第i个vector的第j个下表的元素。

对于string

class string
{
private:char _buf[16];char* _ptr;size_t _size;size_t _capacity;
}

string设计如下,string在设计时用了一个buf的数组,buf大小是16,最后一个空间是给\0的。

这样设计的目的是小于16byte的字符串,存在buf数组中。大于等于16的字符串存在_ptr指向的空间。

list的使用

概念:list是一个容器,允许在常数O(1)时间,在任意位置进行insert和erase。他的迭代器是双向的

链表在使用上和vector和string差不多。

因为支持O(1)的时间,所以它是双向循环链表的数据结构。

如图

对于迭代器的位置,begin()是第一个元素的位置,end()是最后一个元素的下一个位置,也就是哨兵位头结点。

在这里插入图片描述

list的迭代器

对于list为什么要学迭代器?
对于string和vector来说,使用的是原生指针,所以迭代器是原生的,对于list,我们也要封装迭代器,因为list底层是地址,不是连续的地址。为了方便用户操作,比如for循环遍历,范围for等。

小细节:因为list的结构,所以while循环内不能用小于<,因为都是地址,地址不能比大小,迭代器的条件都是不等于!=

 void test1()
{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;
}

反向迭代器

rbegin()就是最后一个元素的下一个位置。

在这里插入图片描述

auto rit = lt.rbegin();while (rit != lt.rend()){cout << *rit << " ";++rit;}

构造函数

四个:无参的构造,n个value的构造,迭代器区间构造,拷贝构造。

和vector非常相似不说,查文档。

关于list::sort的排序

如果大量的排序不建议用list自带的。可以用vector进行排序。
对于std算法库里面的sort,需要传随机迭代器才可以使用。

但是list不支持随机访问,list的迭代器是双向迭代器。

list lt;
lt.sort();

对于迭代器实际上分为三类。
1.单向。++ forward_list
2.双向。致辞 ++ – list
3.随机。支持++ – + - vector

所以要求传双向迭代器的,也可以传随机迭代器。

总结:list不支持随机迭代器,他是双向迭代器,不能用库的sort的原因是因为,库里的sort用的快排,快排用的是随机访问,所以一般不用链表进行排序

解决方法:可以先把数据转移到vector中排序后,再转移到list中。

unique

这个函数的作用是用来去重。

但是去重是有条件的,他只能对排序的list进行去重

list的底层模拟实现

结点类的实现

	template<class T>struct list_node{list_node<T>* _next;list_node<T>* _prev;T _data;list_node(const T& val = T()):_next(nullptr), _prev(nullptr), _data(val){}};

迭代器模拟实现

因为底层空间不连续,地址不连续,所以需要封装迭代器

用模板T的原因是迭代器里封装了结点的指针。

版本1

template <class T>
struct _list_iterator
{typedef list_node<T> Node;Node* _node;T& operator*(){return _node->_data;}}

const迭代器,一般写法就是再定义一个const迭代器的类。这样复用性很差。达不到软件工程复用的思想。

大神写法就是用模板参数 来控制。

这里不用管第一个参数T,第一个参数是数据类型,比如int,只用控制解引用和箭头访问数值的就行。也就是控制Ref和 Ptr

const迭代器第一个位置不加const的原因是因为:需要保持一致的类型。因为在begin()函数中用结点的指针构造迭代器时,传递的是int的类型。但是模板传递过去是cosnt int类型。这时候类型不匹配。

//迭代器实现

	// typedef __list_iterator<T, T&, T*> iterator;// typedef __list_iterator<T, const T&, const T*> const_iterator;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){}// 析构函数  -- 节点不属于迭代器,不需要迭代器释放// 拷贝构造和赋值重载 -- 默认生成的浅拷贝就可以// *itRef operator*(){return _node->_data;}Ptr operator->(){ //return &(operator*());return &_node->_data;}self& operator++(){_node = _node->_next;return *this;}self operator++(int){self tmp(*this);_node = _node->_next;return tmp;}self& operator--(){_node = _node->_prev;return *this;}self operator--(int){self tmp(*this);_node = _node->_prev;return tmp;}bool operator!=(const self& it){return _node != it._node;}bool operator==(const self& it){return _node == it._node;}};

list实现

	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;const_iterator begin() const{// list_node<int>*return const_iterator(_head->_next);}const_iterator end() const{return const_iterator(_head);}iterator begin(){return iterator(_head->_next);//return _head->_next;}iterator end(){return iterator(_head);}list(){_head = new Node();_head->_next = _head;_head->_prev = _head;}// lt2(lt1)/*list(const list<T>& lt){_head = new Node();_head->_next = _head;_head->_prev = _head;for (auto e : lt){push_back(e);}}*/void empty_init(){_head = new Node();_head->_next = _head;_head->_prev = _head;}template <class InputIterator>list(InputIterator first, InputIterator last){empty_init();while (first != last){push_back(*first);++first;}}// 17:00 继续void swap(list<T>& lt){std::swap(_head, lt._head);}// lt2(lt1) -- 现代写法list(const list<T>& lt){empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);}// lt2 = lt1list<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);}}void push_back(const T& x){//Node* tail = _head->_prev;//Node* newnode = new Node(x); _head       tail  newnode//tail->_next = newnode;//newnode->_prev = tail;//newnode->_next = _head;//_head->_prev = newnode;insert(end(), x);}void push_front(const T& x){insert(begin(), x);}void pop_back(){erase(--end());}void pop_front(){erase(begin());}// 插入在pos位置之前iterator insert(iterator pos, const T& x){Node* newNode = new Node(x);Node* cur = pos._node;Node* prev = cur->_prev;// prev  newnode  curprev->_next = newNode;newNode->_prev = prev;newNode->_next = cur;cur->_prev = newNode;return iterator(newNode);}iterator erase(iterator pos){assert(pos != end());Node* cur = pos._node;Node* prev = cur->_prev;Node* next = cur->_next;// prev  nextprev->_next = next;next->_prev = prev;delete cur;return iterator(next);}private:Node* _head;};void print_list(const list<int>& lt){list<int>::const_iterator it = lt.begin();while (it != lt.end()){//*it = 10; // 不允许修改cout << *it << " ";++it;}cout << endl;}

插入的实现

只用实现insert就好,头插尾插复用即可。

这个很简单,轻松实现

迭代器失效

insert

list的insert不存在迭代器失效的问题。因为list不需要像vector一样挪动数据,也不像vector一样扩容出现野指针。lsit的每个结点都是独立的。

erase

erase删掉一个结点时,已经delete了,空间已经被释放了。所以会导致迭代器失效。经典野指针失效

所以erase返回删除位置的下一个位置的迭代器。所以需要重新接收迭代器。

析构函数

析构函数内部直接调用clear(),因为析构时指这个结构不要了,所以直接delete哨兵位结点。

void clear()
{iterator it = begin();while(it != end()){it = erase(it);}
}~list()
{clear();delete _head;_head = nullptr;
}

拷贝构造

拷贝构造函数的规则:我们不写,完成浅拷贝。所以_head被拷贝了一份,指向了同一块空间。

浅拷贝不一定有问题,看对应场合,比如在迭代器中,浅拷贝没有错。因为不用析构。

lsit中我们要完成深拷贝。这里需要析构。

这里先用迭代器区间进行拷贝构造

void empty_init()
{_head = new Node();_head ->_next = _head;_head->_prev = _head;
}template <class InputIterator>
list(InputIterator first, InputIterator last)
{//哨兵位结点必须有empty_init();while(first != last){push_pack(*first);++first;}
}

void swap(list<T>& lt)
{std::swap(_head, lt._head);
}
//lt2(lt1)
//现代写法
list(const list<T>& lt)
{empty_init();list<T> tmp(lt.begin(), lt.end());swap(tmp);
}

赋值构造函数

赋值构造函数返回引用,减少拷贝。返回list的原因是支持连续赋值。

//lt2 = lt1;
list<T>& operator=(list<T> lt)
{swap(lt);return *this;
}
http://www.tj-hxxt.cn/news/45112.html

相关文章:

  • 洛阳网站建设长沙疫情最新数据消息
  • 两个女孩子怎么做网站想做百度推广找谁
  • 网页设计制作一个餐饮网站seo查询工具
  • 公司开发一个网站的流程广州seo网站
  • 公司企业网站怎么建设媒介星软文平台官网
  • 广州建站代运营公司有哪些企业员工培训课程有哪些
  • 网站建设如何跑业务百度网页版官网
  • 一级a做爰全过程片老鸭子网站目前最新的营销方式有哪些
  • 企业的做网站网站推广交换链接
  • iapp如何用网站做软件宁波网站推广公司有哪些
  • 如何给一个网站做优化河南网站推广多少钱
  • 做网站运营好还是SEO好seo关键词排名优化评价
  • 品牌商城网站开发网络推广协议合同范本
  • 旅游网站设计与制作课程设计电商运营基本知识
  • 关于南宁网页的介绍seo排名优化软件价格
  • 微信上做网站编辑百度快速排名平台
  • 小说网站架构seo是指什么意思
  • 宁波 手机网站建设seo经理招聘
  • 做ppt找素材的网站百度竞价系统
  • 厦门网站建设价格xm37北京互联网公司排名
  • 栾川住房和城乡建设委员会网站博客网站
  • 网站搜索功能怎样做海外广告优化师
  • 信息发布型网站建设的特点新媒体seo培训
  • 成都旅游吉林网络seo
  • 遵义网红打卡seo如何优化的
  • 广州网站建设教程百度网页版登录入口官网
  • 做的网站没有手机版2024年疫情还会封控吗
  • 如何做网站品类北大青鸟
  • 网站制作与建立百度推广是什么意思
  • 基于网站的app开发怎么网站排名seo