C++ List容器常用函数接口实例分析

本篇内容主要讲解“C++List容器常用函数接口实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++List容器常用函数接口实例分析”吧!一、基本结构由源代码可知

本篇内容主要讲解“C++ List容器常用函数接口实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++ List容器常用函数接口实例分析”吧!

一、基本结构

由源代码可知,list容器是有一个带头双向循环链表实现,所以我们模拟实现也需要实现一个带头双向循环链表的数据结构。

  1. template<class T>
  2. struct list_node
  3. {
  4. list_node<T>* _next;
  5. list_node<T>* _prev;
  6. T _data;
  7. list_node(const T& val = T())//用一个匿名对象来做缺省参数
  8. :_next(nullptr)
  9. , _prev(nullptr)
  10. , _data(val)
  11. {}
  12. };
  13. template<class T>
  14. class list
  15. {
  16. public:
  17. typedef list_node<T> Node;
  18. private:
  19. Node* _head;
  20. };

二、list的迭代器的构造

list的迭代器与vector的迭代器不一样,list的迭代器是一个自定义类型的对象,成员变量包含一个指向节点的指针。

  1. template<class T, class Ref, class Ptr>
  2. struct __list_iterator
  3. {
  4. typedef list_node<T> Node;
  5. typedef __list_iterator<T, Ref, Ptr> self;
  6. Node* _node;
  7. __list_iterator(Node* node)
  8. :_node(node)
  9. {}
  10. // 析构函数  -- 节点不属于迭代器,不需要迭代器释放
  11. // 拷贝构造和赋值重载 -- 默认生成的浅拷贝就可以
  12. // *it
  13. Ref operator*()
  14. {
  15. return _node->_data;
  16. }
  17. Ptr operator->()
  18. {
  19. //return &(operator*());
  20. return &_node->_data;
  21. }
  22. self& operator++()
  23. {
  24. _node = _node->_next;
  25. return *this;
  26. }
  27. self operator++(int)
  28. {
  29. self tmp(*this);//拷贝构造
  30. _node = _node->_next;
  31. return tmp;//因为tmp出了作用域就不在了,所以不可以引用返回
  32. }
  33. self& operator--()
  34. {
  35. _node = _node->_prev;
  36. return *this;
  37. }
  38. self operator--(int)
  39. {
  40. self tmp(*this);
  41. _node = _node->_prev;
  42. return tmp;
  43. }

⭐️⭐️⭐️即用一个自定义类型封装,通过运算符的重载使迭代器实现像指针一样的操作行为。

三、迭代器的实现

  1. template<class T>
  2. class list
  3. {
  4. typedef list_node<T> Node;
  5. public:
  6. typedef __list_iterator<T, T&, T*> iterator;
  7. typedef __list_iterator<T, const T&, const T*> const_iterator;
  8. //仅仅是为了改名,如果不是为了改名,不用写。
  9. __list_iterator<T, const T&, const T*> begin() const
  10. {
  11. // list_node<int>*
  12. return __list_iterator<T, const T&, const T*>(_head->_next);
  13. //构造一个匿名对象
  14. }
  15. const_iterator end() const
  16. {
  17. return const_iterator(_head);
  18. }
  19. iterator begin()
  20. {
  21. return iterator(_head->_next);//构造一个匿名对象来返回
  22. //return _head->_next;//也可以,因为单参数构造函数支持隐式类型转换。
  23. //iterator it = _head->_next   隐式调用
  24. }
  25. iterator end()
  26. {
  27. return iterator(_head);
  28. }
  29. }

四、insert,erase

  1. // 插入在pos位置之前
  2. iterator insert(iterator pos, const T& x)//pos是一个迭代器对象
  3. {
  4. Node* newNode = new Node(x);
  5. Node* cur = pos._node;
  6. Node* prev = cur->_prev;
  7. // prev  newnode  cur
  8. prev->_next = newNode;
  9. newNode->_prev = prev;
  10. newNode->_next = cur;
  11. cur->_prev = newNode;
  12. return iterator(newNode);
  13. }
  14. iterator erase(iterator pos)
  15. {
  16. assert(pos != end());
  17. Node* cur = pos._node;
  18. Node* prev = cur->_prev;
  19. Node* next = cur->_next;
  20. // prev  next
  21. prev->_next = next;
  22. next->_prev = prev;
  23. delete cur;
  24. return iterator(next);
  25. }

五、push_back,push_front,pop_back,pop_front

  1. void push_back(const T& x)
  2. {
  3. //Node* tail = _head->_prev;
  4. //Node* newnode = new Node(x);
  5.  _head    tail  newnode
  6. //tail->_next = newnode;
  7. //newnode->_prev = tail;
  8. //newnode->_next = _head;
  9. //_head->_prev = newnode;
  10. insert(end(), x);
  11. }
  12. void push_front(const T& x)
  13. {
  14. insert(begin(), x);
  15. }
  16. void pop_back()
  17. {
  18. erase(--end());
  19. //这里不可以用end()-1吧,因为尾部迭代器在尾删后是需要变得
  20. }
  21. void pop_front()
  22. {
  23. erase(begin());
  24. }

⭐️这里均复用了insert和erase函数。

六、构造函数与赋值重载

  1. list()//带头双向循环链表,初始化要先把头弄出来
  2. {
  3. _head = new Node();
  4. //自定义类型去调用对应类的构造函数,带不带这个括号都可
  5. _head->_next = _head;
  6. _head->_prev = _head;
  7. }
  8. // lt2(lt1)————传统写法
  9. /*list(const list<T>& lt)
  10. {
  11. _head = new Node();
  12. _head->_next = _head;
  13. _head->_prev = _head;
  14. for (auto e : lt)
  15. {
  16. push_back(e);//push_back中复用insert,insert中完成深拷贝
  17. }
  18. }*/
  19. void empty_init()
  20. {
  21. _head = new Node();
  22. _head->_next = _head;
  23. _head->_prev = _head;
  24. }
  25. //如果我们写现代写法,那么必须提供相应的带参构造
  26. template <class InputIterator>
  27. list(InputIterator first, InputIterator last)
  28. {
  29. empty_init();
  30. while (first != last)
  31. {
  32. push_back(*first);//push_back中调用insert时会完成相应深拷贝
  33. ++first;
  34. }
  35. }
  36. void swap(list<T>& lt)
  37. {
  38. std::swap(_head, lt._head);//交换头节点
  39. }
  40. // lt2(lt1) -- 现代写法
  41. list(const list<T>& lt)
  42. {
  43. empty_init();//总不能把一个野指针换给别人呀!
  44. list<T> tmp(lt.begin(), lt.end());
  45. swap(tmp);
  46. }
  47. // lt2 = lt1
  48. list<T>& operator=(list<T> lt)
  49. //list<T> lt = lt1,传值传参这一步就调用了拷贝构造完成深拷贝
  50. {
  51. swap(lt);
  52. return *this;
  53. }

⭐️⭐️⭐️注意现代写法的方法

七、析构与清空

  1. ~list()
  2. {
  3. clear();
  4. delete _head;
  5. _head = nullptr;
  6. }
  7. void clear()
  8. {
  9. iterator it = begin();
  10. while (it != end())
  11. {
  12. it = erase(it);//用返回值更新,防止迭代器失效
  13. }
  14. }

到此,相信大家对“C++ List容器常用函数接口实例分析”有了更深的了解,不妨来实际操作一番吧!这里是恰卡网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

本站部分文章来自网络或用户投稿,如无特殊说明或标注,均为本站原创发布。涉及资源下载的,本站旨在共享仅供大家学习与参考,如您想商用请获取官网版权,如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
开发者

css常用font字体属性是什么

2022-8-3 21:16:10

开发者

Java-Redis-Redisson分布式锁的功能如何使用及实现

2022-8-3 21:16:24

搜索