【跟学C++】C++链表——List类(Study11)


 ============================ 【说明】 ===================================================
  大家好,本专栏主要是跟学C++内容,自己学习了这位博主【 AI菌】的【C++21天养成计划】,讲的十分清晰,适合小白,希望给这位博主多点关注、收藏、点赞。
  主要针对所学内容,通过自己的理解进行整理,希望大家积极交流、探讨,多给意见。后面也会给大家更新,其他一些知识。若有侵权,联系删除!共同维护网络知识权利!
 =======================================================================================
   写在前面
  至此,我们了解了C++的基本语法,但是进一步学习C++,数据结构是必不可少的内容。 数据结构与算法决定了代码测存储方式,以及代码执行效率。
  数据结构的重要性不言而喻, 关于数据结构的基本知识可以转至本人另一专栏====>数据结构】。同样也可以阅读博主【 AI菌】写的【 数据结构与算法】,比较通俗易懂,可以学习学习!

1、何为List类?

  list是顺序容器,也可以理解为顺序表。它是允许在表中任意位置进行插入与删除操作的数据结构。
  list顺序容器是双向链表,双向链表可以将所存储的元素存放在不同、不相关的位置。每个元素与前后元素链接,并且保持顺序性。
  与单链表(forward_list)相似,只不过单链表只能向前遍历,因此单链表更小更高效。
  与其他顺序容器(array、vector、queue)相比较,list在插入、删除和移动容器中已经获得迭代器的任何位置的元素时,表现更好。
  listforward_list相比其他顺序容器。主要缺点在于:无法通过索引直接得到元素。

2、List类——成员函数总结

2.1 构造函数

  通过list类内部的多种重载构造函数,初始化list:

#include <iostream>
#include <list>
using namespace std; 

int main ()
{
  // 1.通过几种不同的(重载)构造函数初始化链表 
  list<int> first;                                // 整型空链表
  list<int> second (4,100);                       // 四个值为100的链表
  list<int> third (second.begin(),second.end());  // 链表3:值为链表2的内容
  list<int> fourth (third);                       // 赋值链表3的链表4

  // 2.迭代器可由数组创建,初始化链表 
  int array[] = {16,2,77,29};
  list<int> fifth (array, array + sizeof(array) / sizeof(int) );

  cout << "链表5的内容为: ";
  for (list<int>::iterator it = fifth.begin(); it != fifth.end(); it++)
    cout << *it << ' ';
  return 0;
}

结果:

链表5的内容为: 16 2 77 29

2.2 重载运算符

  使用重载运算符=,可以在原有的链表容器中分配新的内容,替换当前内容,同时修改链表容器大小:

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> first (3);      // 链表first 内容为0 0 0
  list<int> second (5);     // 链表second 内容为0 0 0 0 0

  second = first;
  first = list<int>();

  std::cout << "Size of first: " << int (first.size()) <<endl;
  std::cout << "Size of second: " << int (second.size()) <<endl;
  return 0;

结果:

Size of first: 0
Size of second: 3

2.3 迭代器(iterater)

   => begin & end <=

(1) begin

  begin()返回list容器第一个元素。

(2) end

  end()返回list容器最后一个元素。

  例:

#include <iostream>
#include <list>
using namespace std;

int main()
{
  int array[] = {75,23,65,42,13};
  list<int> mylist(array, array+5);

  cout << "mylist contains:";
  for (list<int>::iterator it=mylist.begin(); it != mylist.end(); ++it)
    std::cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 75 23 65 42 13

注:list::front该成员函数返回的是,指向它的双向迭代器

  

   => rbegin & rend <=

(3) rbegin

  rbegin()r即代表reverse,颠倒,反向迭代器。rbegin则返回最后一个元素。

(4) rend

  rend()r即代表reverse,颠倒,反向迭代器。rbegin则返回第一个元素。

  例:

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist;
  for (int i=1; i<=5; ++i) 
  	mylist.push_back(i);

  cout << "mylist backwards:";
  for (list<int>::reverse_iterator rit=mylist.rbegin(); rit!=mylist.rend(); ++rit)
    cout << ' ' << *rit;
  return 0;
}

结果:

mylist backwards: 5 4 3 2 1

2.4 容量

   => empty <=

(1) empty
   empty() 判断list容器是否为空。

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist;
  int sum (0);

  for(int i=1;i<=10;++i) 
  	mylist.push_back(i);

  while (!mylist.empty())
  {
     sum += mylist.front();
     mylist.pop_front();
  }

  std::cout << "total: " << sum ;
  return 0;
}

结果:

total: 55

  

   => size & max_size <=

(2) size
   size() 返回list容器中元素个数。

(3) max_size
   size() 返回list容器中最大的元素。
  例:

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist;
 
  for (int i=0; i<10; i++) 
  	mylist.push_back(i);
  cout << "size: " << mylist.size() << endl;
  cout << "max_size: " << mylist.max_size() << endl;
  return 0;
}

结果:

size: 10
max_size: 357913941

2.5 访问元素

   => front& back <=

(1) front
   front() 返回list容器中第一个元素。

(2) back
   back() 返回list容器中最后一个元素。

  例:

#include <iostream>
#include <list>
using namespace std;

int main()
{
	list<int> mylist;
	for(int i=1; i<=5; ++i) 
	mylist.push_back(i);
	
	cout<<"第一个元素是:"<<mylist.front()<<endl;
	cout<<"最后一个元素是:"<<mylist.back()<<endl;
	return 0;
}

结果:

第一个元素是:1
最后一个元素是:5

2.6 修改链表

   => push_front & push_back <=

(1) push_front
   push_front() 在初始list容器第一个元素前增加一个数。

(2) push_back
   push_back() 在初始list容器最后一个元素前增加一个数。

  例:

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist(2,100);    // two ints with a value of 100
  cout << "原始的list中各元素:";
  for (list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    cout << ' ' << *it;
  cout<<endl;
  
  mylist.push_front(200);
  mylist.push_front(300);

  cout << "在list前插入元素后:";
  for (list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    cout << ' ' << *it;
  cout <<endl;
  
  mylist.push_back(600);
  cout << "在list后插入元素后:";
  for (list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    cout << ' ' << *it;
  return 0;
}

结果:

原始的list中各元素: 100 100
在list前插入元素后: 300 200 100 100
在list后插入元素后: 300 200 100 100 600

  

   => pop_front & pop_back <=

(3) pop_front
   pop_front() 删除list容器中第一个元素,同时size减1。

(4) pop_back
   pop_back() 删除list容器中最后一个元素,同时size减1。

  例:

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist;
  for(int i=1;i<=5;i++)
  	mylist.push_back(i); 
  cout<<"原list中的元素:";
  for(list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it )
  	cout<<*it<<" ";
  cout<<endl;
  
  mylist.pop_front();
  cout << "删除list开头第一个元素后:";
  for(list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it )
  	cout<<*it<<" ";
  cout<<endl;
  cout<<"list中元素个数:"<<mylist.size()<<endl;
  
  mylist.pop_back();
  cout<<"删除list最后一个元素:";
  for(list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it )
  	cout<<*it<<" ";
  cout<<endl;
  cout<<"list中元素个数:"<<mylist.size()<<endl;
  return 0;
}

结果:

原list中的元素:1 2 3 4 5
删除list开头第一个元素后:2 3 4 5
list中元素个数:4
删除list最后一个元素:2 3 4
list中元素个数:3

  

   => insert <=

(5) insert
   insert() 在指定的位置前插入新元素。

#include <iostream>
#include <list>
#include <vector>
using namespace std;

int main ()
{
  list<int> mylist;
  list<int>::iterator it;  //声明it为迭代器 

  for(int i=1; i<=5; ++i) mylist.push_back(i); // 1 2 3 4 5

  it = mylist.begin();
  ++it;       // it points now to number 2           ^
  mylist.insert (it,10);                        // 1 10 2 3 4 5

  // "it" still points to number 2                      ^
  mylist.insert (it,2,20);                      // 1 10 20 20 2 3 4 5

  --it;   // it points now to the second 20            ^

  std::vector<int> myvector (2,30);
  mylist.insert (it,myvector.begin(),myvector.end());   // 1 10 20 30 30 20 2 3 4 5
                                                    
  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 1 10 20 30 30 20 2 3 4 5

  

   => erase <=

(6) erase
  erase() 移除list容器中某个元素某个范围内的元素。

#include <iostream>
#include <list>
using namespace std;

int main ()
{
  list<int> mylist;
  list<int>::iterator it1,it2;
  // set some values:
  for (int i=1; i<10; ++i) mylist.push_back(i*10);
                              // 10 20 30 40 50 60 70 80 90
  it1 = it2 = mylist.begin(); // ^^
  advance (it2,6);            // ^                 ^
  ++it1;                      //    ^              ^
  it1 = mylist.erase(it1);   // 10 30 40 50 60 70 80 90
                              //    ^           ^

  it2 = mylist.erase(it2);   // 10 30 40 50 60 80 90
                              //    ^           ^

  ++it1;                      //       ^        ^
  --it2;                      //       ^     ^

  mylist.erase (it1,it2);     // 10 30 60 80 90
                              //        ^
  cout << "mylist contains:";
  for (it1=mylist.begin(); it1!=mylist.end(); ++it1)
    cout << ' ' << *it1;
  return 0;
}

结果:

mylist contains: 10 30 60 80 90

  

   => swap <=

(7) swap
  list1.swap(list2) list1容器与list2容器整体互换。

#include <iostream>
#include <list>

int main ()
{
  std::list<int> first (3,100);   // three ints with a value of 100
  std::list<int> second (5,200);  // five ints with a value of 200

  first.swap(second);

  std::cout << "first contains:";
  for (std::list<int>::iterator it=first.begin(); it!=first.end(); it++)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "second contains:";
  for (std::list<int>::iterator it=second.begin(); it!=second.end(); it++)
    std::cout << ' ' << *it;
  return 0;
}

结果:

first contains: 200 200 200 200 200
second contains: 100 100 100

  

   => resize <=

(8) resize
  resize() 调整list容器的大小,使容器包含n个元素。
  若n<当前容器大小,则容器内的元素个数减少至n个元素,其他元素删除(销毁);
  若n>当前容器大小,则容器在尾部补上所需元素,使容器元素个数达到n个,默认补0,若指定元素值,则list.resize(n,value)value为指定元素值。

#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;
  // set some initial content:
  for (int i=1; i<10; ++i) mylist.push_back(i); //1 2 3 4 5 6 7 8 9

  mylist.resize(5);  //1 2 3 4 5 
  mylist.resize(8,100);  //1 2 3 4 5 100 100 100
  mylist.resize(12);  //1 2 3 4 5 100 100 100 0 0 0 0

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 1 2 3 4 5 100 100 100 0 0 0 0

  

   => clear <=

(9) clear
  clear() 删除list容器所有元素,使容器size为0。

#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;
  std::list<int>::iterator it;

  mylist.push_back (100);
  mylist.push_back (200);
  mylist.push_back (300);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  mylist.clear(); //清空所有元素 
  mylist.push_back (1101);
  mylist.push_back (2202);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 100 200 300
mylist contains: 1101 2202

2.7 其他

   => remove & remove_if <=

(1) remove
  remove(value) 删除list容器中所有与value相同的元素,并减小size值。
  remove()与上面所述的erase()不一样,erase作为迭代器删除元素,而remove()则是依据元素值删除元素。

#include <iostream>
#include <list>

int main ()
{
  int myints[]= {5,6,8,8,9,45,8};
  std::list<int> mylist (myints,myints+7);

  mylist.remove(8); //删除链表中所有为8的元素 

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 5 6 9 45

(2) remove_if
  remove_if(condition)依据condition条件删除容器中部分元素。

#include <iostream>
#include <list>

// a predicate implemented as a function:
bool single_digit (const int& value) { return (value<10); }

// a predicate implemented as a class:
struct is_odd {
  bool operator() (const int& value) { return (value%2)==1; }
};

int main ()
{
  int myints[]= {15,36,7,17,20,39,4,1};
  std::list<int> mylist (myints,myints+8);   // 15 36 7 17 20 39 4 1

  mylist.remove_if (single_digit);           // 15 36 17 20 39

  mylist.remove_if (is_odd());               // 36 20

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 36 20

  

   => unique <=

(3) unique
  list.unique()删除容器中相同的元素,只保留最前面(第一个)元素。
  list.unique(condition)删除容器中不符合condition的元素。

#include <iostream>
#include <cmath>
#include <list>

// 判断元素整数部分相同 
bool same_integral_part (double first, double second)
{ return ( int(first)==int(second) ); }

// 判断相邻元素距离是否小于5 
struct is_near {
  bool operator() (double first, double second)
  { return (fabs(first-second)<5.0); }
};

int main ()
{
  double mydoubles[]={ 12.15,  2.72, 73.0,  12.77,  3.14,
                       12.77, 73.35, 72.25, 15.3,  72.25 };
  std::list<double> mylist (mydoubles,mydoubles+10);
   
  mylist.sort();             //  2.72,  3.14, 12.15, 12.77, 12.77,
                             // 15.3,  72.25, 72.25, 73.0,  73.35
  //版本1 
  mylist.unique();           //  2.72,  3.14, 12.15, 12.77
                             // 15.3,  72.25, 73.0,  73.35
  //版本2 
  mylist.unique (same_integral_part);  //  2.72,  3.14, 12.15
                                       // 15.3,  72.25, 73.0
  
  mylist.unique (is_near());           //  2.72, 12.15, 72.25

  std::cout << "mylist contains:";
  for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 2.72 12.15 72.25

  

   => sort <=

(4) sort
  list.sort()依据ASCII码进行排序。
  list.sort(comp)依据自定义规则comp排序。

#include <iostream>
#include <list>
#include <string>
#include <cctype>

// comparison, not case sensitive.
bool compare_nocase (const std::string& first, const std::string& second)
{
  unsigned int i=0;
  while ( (i<first.length()) && (i<second.length()) )
  {
    if (tolower(first[i])<tolower(second[i])) return true;
    else if (tolower(first[i])>tolower(second[i])) return false;
    ++i;
  }
  return ( first.length() < second.length() );
}

int main ()
{
  std::list<std::string> mylist;
  std::list<std::string>::iterator it;
  mylist.push_back ("one");
  mylist.push_back ("two");
  mylist.push_back ("Three");

  mylist.sort();

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  mylist.sort(compare_nocase);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

结果:

mylist contains: Three one two
mylist contains: one Three two

  

   => reverse<=

(5) reverse
  list.reverse()颠倒list容器中的元素,注意区别上面swap()成员函数的用法。

#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;

  for (int i=1; i<10; ++i) mylist.push_back(i);

  mylist.reverse();

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  return 0;
}

结果:

mylist contains: 9 8 7 6 5 4 3 2 1

3、总结

  最后,长话短说,大家看完就好好动手实践一下,切记不能三分钟热度、三天打鱼,两天晒网。大家也可以自己尝试写写博客,来记录大家平时学习的进度,可以和网上众多学者一起交流、探讨,我也会及时更新,来督促自己学习进度。一开始提及的博主【AI菌】,个人已关注,并订阅了相关专栏(对我有帮助的),希望大家觉得不错的可以点赞、关注、收藏。

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

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340