C++中list用法详解[通俗易懂]

C++中list用法详解[通俗易懂]1.关于list容器list是一种序列式容器。list容器完成的功能实际上和数据结构中的双向链表是极其相似的,list中的数据元素是通过链表指针串连成逻辑意义上的线性表,也就是list也具有链表的主要优点,即:在链表的任一位置进行元素的插入、删除操作都是快速的。list的实现大概是这样的:list的每个节点有三个域:前驱元素指针域、数据域和后继元素指针域。前驱元素指针域保存了前驱元素的首地

大家好,又见面了,我是你们的朋友全栈君。

1.关于list容器

list是一种序列式容器。list容器完成的功能实际上和数据结构中的双向链表是极其相似的,list中的数据元素是通过链表指针串连成逻辑意义上的线性表,也就是list也具有链表的主要优点,即:在链表的任一位置进行元素的插入、删除操作都是快速的。list的实现大概是这样的:list的每个节点有三个域:前驱元素指针域、数据域和后继元素指针域。前驱元素指针域保存了前驱元素的首地址;数据域则是本节点的数据;后继元素指针域则保存了后继元素的首地址。其实,list和循环链表也有相似的地方,即:头节点的前驱元素指针域保存的是链表中尾元素的首地址,list的尾节点的后继元素指针域则保存了头节点的首地址,这样,list实际上就构成了一个双向循环链。由于list元素节点并不要求在一段连续的内存中,显然在list中是不支持快速随机存取的,因此对于迭代器,只能通过“++”或“–”操作将迭代器移动到后继/前驱节点元素处。而不能对迭代器进行+n或-n的操作,这点,是与vector等不同的地方。

 

我想把三个常用的序列式放在一起对比一下是有必要的:

vector : vector和built-in数组类似,拥有一段连续的内存空间,能非常好的支持随即存取,即[]操作符,但由于它的内存空间是连续的,所以在中间进行插入和删除会造成内存块的拷贝,另外,当插入较多的元素后,预留内存空间可能不够,需要重新申请一块足够大的内存并把原来的数据拷贝到新的内存空间。这些影响了vector的效率,但是实际上用的最多的还是vector容器,建议大多数时候使用vector效率一般是不错的。vector的用法解析可以参考本人的另一篇随笔:http://www.cnblogs.com/BeyondAnyTime/archive/2012/08/08/2627666.html

list:      list就是数据结构中的双向链表(根据sgi stl源代码),因此它的内存空间是不连续的,通过指针来进行数据的访问,这个特点使得它的随即存取变的非常没有效率,因此它没有提供[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。

deque: deque是一个double-ended queue,它的具体实现不太清楚,但知道它具有以下两个特点:它支持[]操作符,也就是支持随即存取,并且和vector的效率相差无几,它支持在两端的操作:push_back,push_front,pop_back,pop_front等,并且在两端操作上与list的效率也差不多。

 

因此在实际使用时,如何选择这三个容器中哪一个,应根据你的需要而定,具体可以遵循下面的原则
1. 如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector
2. 如果你需要大量的插入和删除,而不关心随即存取,则应使用list
3. 如果你需要随即存取,而且关心两端数据的插入和删除,则应使用deque。

 

2.list中常用的函数

2.1list中的构造函数:

list() 声明一个空列表;

list(n) 声明一个有n个元素的列表,每个元素都是由其默认构造函数T()构造出来的

list(n,val) 声明一个由n个元素的列表,每个元素都是由其复制构造函数T(val)得来的

list(n,val) 声明一个和上面一样的列表

list(first,last) 声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素


2.2 begin()和end():通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator,可以调用list容器的 end() 函数来得到list末端下一位置,相当于:int a[n]中的第n+1个位置a[n],实际上是不存在的,不能访问,经常作为循环结束判断结束条件使用。


2.3 push_back() 和push_front():使用list的成员函数push_back和push_front插入一个元素到list中。其中push_back()从list的末端插入,而 push_front()实现的从list的头部插入。


2.4 empty():利用empty() 判断list是否为空。


2.5 resize(): 如果调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除,如果需要扩展那么调用默认构造函数T()将元素加到list末端。如果调用resize(n,val),则扩展元素要调用构造函数T(val)函数进行元素构造,其余部分相同。


2.6 clear(): 清空list中的所有元素。


2.7 front()和back(): 通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。但是有一点要注意,就是list中元素是空的时候,这时候调用front()和back()会发生什么呢?实际上会发生不能正常读取数据的情况,但是这并不报错,那我们编程序时就要注意了,个人觉得在使用之前最好先调用empty()函数判断list是否为空。


2.8 pop_back和pop_front():通过删除最后一个元素,通过pop_front()删除第一个元素;序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。


2.9 assign():具体和vector中的操作类似,也是有两种情况,第一种是:l1.assign(n,val)将 l1中元素变为n个T(val)。第二种情况是:l1.assign(l2.begin(),l2.end())将l2中的从l2.begin()到l2.end()之间的数值赋值给l1。


2.10 swap():交换两个链表(两个重载),一个是l1.swap(l2); 另外一个是swap(l1,l2),都可能完成连个链表的交换。


2.11 reverse():通过reverse()完成list的逆置。


2.12 merge():合并两个链表并使之默认升序(也可改),l1.merge(l2,greater<int>()); 调用结束后l2变为空,l1中元素包含原来l1 和 l2中的元素,并且排好序,升序。其实默认是升序,greater<int>()可以省略,另外greater<int>()是可以变的,也可以不按升序排列。

看一下下面的程序:

C++中list用法详解[通俗易懂]

复制代码
 1 #include <iostream>
 2 #include <list>
 3 
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     list<int> l1;
 9     list<int> l2(2,0);
10     list<int>::iterator iter;
11     l1.push_back(1);
12     l1.push_back(2);
13     l2.push_back(3);
14     l1.merge(l2,greater<int>());//合并后升序排列,实际上默认就是升序
15     for(iter = l1.begin() ; iter != l1.end() ; iter++)
16     {
17         cout<<*iter<<" ";
18     }
19     cout<<endl<<endl;
20     if(l2.empty())
21     {
22         cout<<"l2 变为空 !!";
23     }
24     cout<<endl<<endl;
25     return 0;
26 }
复制代码

运行结果:

C++中list用法详解[通俗易懂]


2.13 insert():在指定位置插入一个或多个元素(三个重载):

l1.insert(l1.begin(),100); 在l1的开始位置插入100。

l1.insert(l1.begin(),2,200); 在l1的开始位置插入2个100。

l1.insert(l1.begin(),l2.begin(),l2.end());在l1的开始位置插入l2的从开始到结束的所有位置的元素。


2.14 erase():删除一个元素或一个区域的元素(两个重载)

l1.erase(l1.begin()); 将l1的第一个元素删除。

l1.erase(l1.begin(),l1.end()); 将l1的从begin()到end()之间的元素删除。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/158114.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • listview排序功能_vba listview 控件

    listview排序功能_vba listview 控件usingSystem.Collections; privatevoidlistView2_ColumnClick(objectsender,ColumnClickEventArgse)//排序{   this.listView2.ListView

  • ldap服务器是什么

    ldap服务器是什么LDAP服务器简单来说它是一种得到某些数据的快捷方式,同时LDAP服务器也是一个协议,它经常被用作集体的地址本使用,甚至可以做到更加庞大。它是一种特殊的数据库,与一般的数据库相比有很大的差距,LDAP服务器的读性与一般服务器相比更加优秀。同时LDAP服务器在查询上总了很多的优化,所以利用它可以快速查询出想要得到的结果,当然它也有缺陷,比如在更新方面,它会更新的很慢。LDAP服务器的目录有哪些优势…

  • 基于Apache的反向代理服务器

    基于Apache的反向代理服务器众所周知Apache是目前最优秀的HTTP服务器。实际上它不仅能当作服务器使用,也能够被用来架设代理服务器。本文就如何使用Apache架设HTTP代理服务器进行说明。本文将基于Win32版的Apache2.0.47进行说明。以前的Apache1.x版配置方法稍有不同,但这里不作说明。 首先是Apache的安装。从http://www.apache.org上下载Apache的安装

    2022年10月20日
  • 多个UpdatePanel控件相互引发刷新的使用

    多个UpdatePanel控件相互引发刷新的使用ScriptManager和UpdatePanel控件联合使用可以实现页面异步局部更新的效果。其中的UpdatePanel就是设置页面中异 步局部更新区域,它必须依赖于ScriptManager存在,因为ScriptManger控件提供了客户端脚本生成与管理UpdatePanel的功 能。几个重要的属性:    ScriptManager控件的EnablePartialRendering属

  • 报错注入学习[通俗易懂]

    报错注入学习[通俗易懂]复习完sqlilabs1-4关熟悉了简单sql注入的payload,不用反复看wp的payload,学到了可以0x5c:/%23:#%20:(空格)0x7e=~-1′)unionselect1,(selectgroup_concat(username,0x5c,password)fromusers),3%23遇到第五关报错注入学习文章1学习文章2学习笔记:报错注入原理:报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出…

  • 去除字符串中的双引号「建议收藏」

    去除字符串中的双引号「建议收藏」str为“123”如果一个双引号:str1=str.replace(“\””,””).replace(“\””,””);如果不确定有多少个双引号:str2=str.replace(/\”/g,””);此方法为替换,也可用于去除制定字符,如:Stringstr=”12/3″;str1=str.replace(“\/”,””);str2=str.replace(/\//g,

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号