iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++数据结构中list的示例分析
  • 682
分享到

C++数据结构中list的示例分析

2023-06-25 16:06:42 682人浏览 八月长安
摘要

小编给大家分享一下c++数据结构中list的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!前言list相较于vector来说会显得复杂,它的好处是在任意位置插入,删除都是一个O(1)的时间复杂度。一、list的节点

小编给大家分享一下c++数据结构中list的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

    前言

    list相较于vector来说会显得复杂,它的好处是在任意位置插入,删除都是一个O(1)的时间复杂度。

    一、list的节点

    template <class T>struct __list_node {  typedef void* void_pointer;  void_pointer next;  void_pointer prev;  T data;};

    这个是在stl3.0版本下的list的节点的定义,节点里面有一个前指针,一个后指针,有一个数据data。这里只能知道他是一个双向链表,我们可以再稍微看一下list关于它的构造函数

    class list  --> list() { empty_initialize();   void empty_initialize() {     node = get_node();    node->next = node;    node->prev = node;  }

    再看一下它的list(),可以看出他调用的empty_initialize(),是创建了一个头结点,并且是一个循环的结构。

    综上:list的总体结构是一个带头循环双向链表

    二、list的迭代器

    迭代器通常是怎么使用的,看一下下面这段代码。

    int main(){list<int> l;l.push_back(1);l.push_back(2);l.push_back(3);l.push_back(4);l.push_back(5);l.push_back(6);list<int>::iterator it = l.begin();while (it != l.end()){cout << *it << " ";it++;}cout << endl;return 0;}
    • 我们从list< int >当中定义一个iterator对象,然后让他去访问我们的节点

    • 并且他所支持的操作有++,解引用,当然还有 --等等

    stl3.0当中的迭代器实现:

    template<class T, class Ref, class Ptr>struct __list_iterator {  typedef __list_iterator<T, T&, T*>             iterator;  typedef __list_iterator<T, const T&, const T*> const_iterator;  typedef __list_iterator<T, Ref, Ptr>           self;  typedef bidirectional_iterator_tag iterator_cateGory;  typedef T value_type;  typedef Ptr pointer;  typedef Ref reference;  typedef __list_node<T>* link_type;  typedef size_t size_type;  typedef ptrdiff_t difference_type;  link_type node;  __list_iterator(link_type x) : node(x) {}  __list_iterator() {}  __list_iterator(const iterator& x) : node(x.node) {}  bool operator==(const self& x) const { return node == x.node; }  bool operator!=(const self& x) const { return node != x.node; }  reference operator*() const { return (*node).data; }#ifndef __SGI_STL_NO_ARROW_OPERATOR  pointer operator->() const { return &(operator*()); }#endif   self& operator++() {     node = (link_type)((*node).next);    return *this;  }  self operator++(int) {     self tmp = *this;    ++*this;    return tmp;  }  self& operator--() {     node = (link_type)((*node).prev);    return *this;  }  self operator--(int) {     self tmp = *this;    --*this;    return tmp;  }

    大家感兴趣可以先看看上面的,我们先用一个简述版的来带大家简要实现一下

    template<class T>class __list_node{public:__list_node(const T& val = T())//用一个全缺省比较好:_next(nullptr),_pre(nullptr),node(val){}public:__list_node<T>* _next;__list_node<T>* _pre;T node;};template<class T>class __list_itertaor//这里是迭代器{public:typedef __list_node<T>  Node;__list_itertaor(Node* node){_node = node;}bool operator!=(const __list_itertaor<T>& it){return _node != it._node;}__list_itertaor<T>& operator++(){_node = _node->_next;return *this;}T& operator*(){return _node->node;}private:Node* _node;};

    这里的实现是不完整的,但是很适合说明问题。通过我们去重载opertaor++,和重载opertaor*,可以让我们像指针一样去访问一个节点,让我们可以跟vector和string一样用同样的接口就能实现对数据的访问,这是非常厉害的一个技术。

    注意点:

    • 我们通过对节点的操作,重载了operator++等接口实现了对一个节点的访问,访问的时候实际上也就是创建迭代器对象,对我们的数据进行访问,所以我们封装的时候是将节点的指针进行封装。

    • list相比vector,正因为他们的底层结构不相同,list的迭代器在插入操作和接合操作(splice)都不会造成迭代器失效,只有删除的时候,只有那个被删除元素的迭代器失效,而不影响后面的,而vector就统统失效了。

    模板参数为什么是三个

    2.1 const 迭代器

    有这样一种情况,我们需要const对象去遍历,假如我们有个函数叫做print_list(const list< int >& lt);
    传参: 其中传参中const是因为不会对对象进行修改,加引用是因为不用深拷贝,提高效率。
    功能: 这个函数就是去打印链表里面的内容的。但是按照我们上面的实现,会出现什么问题呢。

    C++数据结构中list的示例分析

    这很正常,在const迭代器就去生成const迭代器对象,在vector,string这些迭代器就是原生指针的时候我们只需要typedef const T* const_iterator,那如果我们在我们生成的list也做类似的操作,来看看结果。

    C++数据结构中list的示例分析

    结果我们发现,好像没多大问题,但是我们尝试修改const迭代器里面的内容时,却发现能修改成功。const迭代器怎么能修改里面的数据呢?这就有问题了!!!说明我们的有一个巨大的隐患在里面。

    C++数据结构中list的示例分析

    2.2 修改方法

    最简单的方法当然就是再写多一个迭代器,把__list_iterator换成__list_const_iterator 之类的,但是我们认真观察的话,实际上这两个类很多东西是重复的,只有在operator*,operator->时所需要的返回值,我们需要找到一种方法去让const对象的返回值也是const对象,答案就是添加多两个个模板参数。
    以下以添加一个模板参数为例,实现一个Ref operator*();

    template<class T>class __list_node{public:__list_node(const T& val = T())//用一个全缺省比较好:_next(nullptr),_pre(nullptr),node(val){}public:__list_node<T>* _next;__list_node<T>* _pre;T node;};template<class T,class Ref>class __list_itertaor{public:typedef __list_node<T>  Node;__list_itertaor(Node* node){_node = node;}bool operator!=(const __list_itertaor<T,Ref>& it){return _node != it._node;}__list_itertaor<T,Ref>& operator++(){_node = _node->_next;return *this;}Ref operator*()//返回Ref,返回值就有区别啦{return _node->node;}private:Node* _node;};template<class T>class list{typedef __list_node<T>  Node;public:typedef __list_itertaor<T,T&> iterator;typedef __list_itertaor<T, const T&> const_iterator;//修改iterator begin(){return iterator(_node->_next);}iterator end(){return iterator(_node);}const_iterator begin()const{return const_iterator(_node->_next);}const_iterator end()const{return const_iterator(_node);}list(){_node = new Node;_node->_next = _node;_node->_pre = _node;}void push_back(const T& val){Node* newnode = new Node(val);Node* tail = _node->_pre;tail->_next = newnode;newnode->_pre = tail;newnode->_next = _node;_node->_pre = newnode;}private:Node* _node;};

    一图了解:也就是我们的测试端test函数中定义list< int >::const_iterator cit= l.begin();的时候迭代器对象就会识别到定义的const迭代器,它的第二个模板参数放的就是const T&,这样子我们operator*()返回的时候只需要返回第二个模板参数就可以了

    C++数据结构中list的示例分析

    同理,我们要用到的接口operator->当中也会有const对象和普通对象调用的情况。我们这里把实现的代码放出来,有需要的自取。

    –》码云链接《–

    二、美中不足

    list上面说的仿佛都是优点

    任意位置的O(1)时间的插入删除,迭代器失效的问题变少了。但他又有哪些不足呢

    • 不支持随机访问

    • 排序的效率慢,库中的sort用的是归并排序–>快排需要三数取中,对于链表来说实现出来效率也低,所以当链表的元素需要进行排序的时候,我们通常也都会拷贝到vector当中,再用vector当中的排序。

    • 同理链表的逆置效率也不高!

    三、迭代器的分类

    迭代器从功能角度来看的话分为:const迭代器/普通迭代器 + 正反向。

    容器底层结构角度分为:单向,双向,随机。

    • 单向: 单链表迭代器(forward_list)/哈希表迭代器;这些只支持单向++;

    • 双向: 双链表迭代器/map迭代器;这些支持的++/- -操作;

    • 随机迭代器: string/vector/deque;这些是支持++/- -/+/-操作的,类似原生指针一般。

    我们来看一下部分函数的,比如sort当中的模板参数写成RandoMaccessIterator,就是想要明示使用者他这里需要的是一个随机的迭代器,在它的底层会调用到迭代器的+操作,所以这个时候如果你传的是一个双向或者单向的迭代器就不行了!!

    //sort的函数声明template <class RandomAccessIterator>  void sort (RandomAccessIterator first, RandomAccessIterator last);custom (2)template <class RandomAccessIterator, class Compare>  void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

    比如说reverse函数声明,它的模板参数是BidirectionalIterator,也就是需要一个支持双向的迭代器,这个时候其实我们就可以传随机迭代器和双向迭代器,从上面的迭代器支持的操作可以看到,随机迭代器是支持双向迭代器的所有操作的
    同理,如果是一个需要单向迭代器的地方,我们就可以传一个双向,随机,单向迭代器了!!

    std::reversetemplate <class BidirectionalIterator>  void reverse (BidirectionalIterator first, BidirectionalIterator last);

    从stl3.0当中的stl_iterator.h,我们可以看出当中的继承关系。这个我们之后再讲。

    C++数据结构中list的示例分析

    注意:difference_type为两个迭代器之间的距离。类型ptrdiff_t为无符号整形。

    3.x std::find的一个报错

    当我们实现了自己的数据结构,如list,我们如果用库里的std:find查找我们实现的数据结构当中的数据会报错。博主的测试版本为vs2013,在其他版本可能不做检查,不会报错。

    void test_list(){list<int> l;l.push_back(5);list<int>::iterator it = std::find(l.begin(), l.end(), 5);}

    报错:这里的报错说的是iterator_category不在我们的迭代器当中,这个是对我们迭代器类型的一个检查。

    C++数据结构中list的示例分析

    stl_list.h当中为迭代器添加了如下声明来解决这个问题。

    C++数据结构中list的示例分析

    解决方案: 我们可以用stl3.0版本下stl_list.h当中的迭代器的声明。也可以用release版本下,都是可以跑过的。

    typedef bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef ptrdiff_t difference_type;

    C++数据结构中list的示例分析

    看完了这篇文章,相信你对“C++数据结构中list的示例分析”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网其他教程频道,感谢各位的阅读!

    --结束END--

    本文标题: C++数据结构中list的示例分析

    本文链接: https://www.lsjlt.com/news/306125.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • C++数据结构中list的示例分析
      小编给大家分享一下C++数据结构中list的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!前言list相较于vector来说会显得复杂,它的好处是在任意位置插入,删除都是一个O(1)的时间复杂度。一、list的节点...
      99+
      2023-06-25
    • C++ 数据结构中单链表的示例分析
      小编给大家分享一下C++ 数据结构中单链表的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、链表是什么链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接依次实现的...
      99+
      2023-06-29
    • Java中数据结构的示例分析
      这篇文章将为大家详细讲解有关Java中数据结构的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1.1.1.       增量内存分配 ArrayList 、 Hash...
      99+
      2023-06-03
    • C++数据结构红黑树的示例分析
      这篇文章给大家分享的是有关C++数据结构红黑树的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。概念和性质红黑树的概念: 红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或...
      99+
      2023-06-29
    • JavaScript数据结构中串的示例分析
      这篇文章将为大家详细讲解有关JavaScript数据结构中串的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体如下:类似于线性表的顺序存储结构,用一组地址连续的...
      99+
      2024-04-02
    • Java数据结构中图的示例分析
      这篇文章给大家分享的是有关Java数据结构中图的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。有向图有向图的定义及相关术语定义∶ 有向图是一副具有方向性的图,是由一组顶点和一组有方向的边组成的,每条方向的...
      99+
      2023-06-29
    • python数据结构堆的示例分析
      小编给大家分享一下python数据结构堆的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!1、说明堆是用数据结构来实现的一种算法:树,数组均可。堆本身是一棵完全二叉树。2、特点最大堆:所有父节点的值大于子节点的值最小...
      99+
      2023-06-15
    • Python Pandas数据结构的示例分析
      这篇文章将为大家详细讲解有关Python Pandas数据结构的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1 Pandas介绍2008年WesMcKinney开发出的库专门用于数据挖...
      99+
      2023-06-29
    • JS中数据结构之栈的示例分析
      这篇文章给大家分享的是有关JS中数据结构之栈的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。栈是一种高效的数据结构,因为数据只能在栈顶添加或删除,所以这样的操作很快,而且...
      99+
      2024-04-02
    • JDK 1.8中HashMap数据结构的示例分析
      这篇文章给大家分享的是有关JDK 1.8中HashMap数据结构的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。概述JDK 1.8对HashMap361天恒平台制作,进行了比较大的优化,底层实现由之前的“...
      99+
      2023-06-04
    • C语言数据结构之绪论的示例分析
      小编给大家分享一下C语言数据结构之绪论的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!绪论什么是数据结构?不同于计算机操作培训,注意与程序设计的区别。Ex...
      99+
      2023-06-20
    • C++数据结构关于栈迷宫示例分析
      这篇文章主要讲解了“C++数据结构关于栈迷宫示例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++数据结构关于栈迷宫示例分析”吧!一、实验目的理解栈的抽象数据类型定义及操作特点。掌握顺...
      99+
      2023-06-21
    • C语言数据结构堆排序示例分析
      今天小编给大家分享一下C语言数据结构堆排序示例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。TOP.堆排序前言什么是堆排...
      99+
      2023-06-30
    • Redis中数据结构与数据操作的示例分析
      小编给大家分享一下Redis中数据结构与数据操作的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Redis完成数据操作的...
      99+
      2024-04-02
    • ES6中Set和Map数据结构的示例分析
      这篇文章主要介绍了ES6中Set和Map数据结构的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。ES6 的 Set:ES6 提供了新...
      99+
      2024-04-02
    • Python数据结构创建的示例分析
      本篇文章为大家展示了Python数据结构创建的示例分析,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。 列表list:变量赋值方式:shoplist = ['apple', '...
      99+
      2023-06-17
    • python数据结构算法的示例分析
      小编给大家分享一下python数据结构算法的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1.算法分析的定义有这样一个问题:当两个看上去不同的程序 解决同...
      99+
      2023-06-22
    • PHP数据结构中图遍历的示例分析
      这篇文章将为大家详细讲解有关PHP数据结构中图遍历的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。图的遍历:深度优先与广度优先树的遍历演化到图的遍历还记得在树的学习中,我们讲到过先序、中序、后序以...
      99+
      2023-06-20
    • 基于C++的数据结构实例分析
      本篇内容介绍了“基于C++的数据结构实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!数据结构通常情况下,精心选择的数据结构可以带来更高...
      99+
      2023-07-02
    • PHP数据结构之图存储结构的示例分析
      这篇文章主要介绍PHP数据结构之图存储结构的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!图的存储结构图的概念介绍得差不多了,大家可以消化消化再继续学习后面的内容。如果没有什么问题的话,我们就继续学习接下来的...
      99+
      2023-06-20
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作