C++STL list容器 基本概念 构造函数 赋值和交换 大小 插入和删除

1 list基本概念

功能: 将数据进行链式存储

链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的。之前学习的vector(单端)、deque(双端,中控器地址连续,缓冲区数据连续)、stack(单端,先进后出栈)、queue(双端,先进先出栈)这些在物理存储单元上都是连续的存储结构。

链表的组成: 链表由一系列结点组成

结点的组成: 一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域
在这里插入图片描述
说明:

  1. 数组物理结构连续,可以遍历每一个数据。但链表中每一个数据是独立的,只能通过当前数据的指针来访问下一个数据。
  2. 链表优点:可以对任意位置进行快速的插入和删除元素。
  • 对数组而言,如果想在20插一个数,只能把20之后的数往后移动一个位置才能插入;如果要删除20,要把20之后的数往前移动。如果数据量很大,需要移动大量的数据。
  • 对于链表而言,如果要在20插入一个数,只需要把20的指针域存储新数据的地址,新数据的指针域再维护30的地址即可。如果要删除20,直接把10的指针域维护的地址改成30的地址即可。相比于数组,链表的插入和删除非常快速。
  1. 链表缺点: 容器遍历速度没有数组快,占用空间(指针域和数据域)比数组大。
  • 因为数组是连续的,遍历快;链表只能通过指针与访问。
  • 就以图中例子而言,数组四个整型数据10、20、30、40,只需要4×4=16个字节,但是链表既有数据域4×4=16个字节,也有指针域4×4=16个字节,占用32个字节,是数组的两倍。
  1. 数组的缺点就是链表的优点,链表的缺点就是数组的优点。

STL中提供的链表:
在这里插入图片描述

  1. STL中的链表是一个双向循环链表
  2. 双向: 链表由节点构成,每个节点有一个数据域和两个指针域,一个指针pre存储前一个节点的地址,另一个指针next维护下一个节点的地址
  3. 循环: 如果不循环,最后一个节点next指向null即可。循环的话,最后一个节点next指向第一个节点,第一个节点的pre指向最后一个节点。
  4. STL中的链表提供了如下对外接口:
  • 头尾的插入push_front()、push_back() 和头尾的删除pop_front()、pop_back()
  • 起始迭代器begin(),指向第一个元素;结束迭代器end(),指向最后一个元素的下一个位置
  • front()指向第一个数据data1,back()指向最后一个数据data4
  • 还有其他对外接口,大小、插入、存取数据等等
  1. 双向迭代器: 由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,begin()和end()都只能通过指针域一个一个地移动,不能跳跃
  2. 采用动态存储分配,不会造成内存浪费和溢出。比如在数组中会留出10000多的数据内存来存放,之前巧用swap进行内存空间收缩的学习笔记也可以证明这一点,但在链表中10000个数据只占用10000个数据的内存。
  3. List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。也就是说,假设某个迭代器指向data3,如果在list中某个位置插入一个新元素,并不会影响这个迭代器的指向,因为list每个数据都是独立的。但如果是数组插入一个数据,这个迭代器的指向就可能发生变化。例如,一个满的数组,再插入一个新数据的话,需要重新找一块内存,此时数组地址发生了变化,这个迭代器就失效了,因为它还指向原来的数组位置。

总结:

  1. STL中List和vector是两个最常被使用的容器,各有优缺点,根据容器的优缺点选择使用。
  2. list的优点:采用动态存储分配,不会造成内存浪费和溢出;链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
  3. list的缺点:链表灵活,但是空间(指针域) 和 时间(遍历)额外耗费较大

2 list构造函数

功能描述: 创建list容器

函数原型:

  • list<T> lst; //list采用采用模板类实现,对象的默认构造形式:
  • list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身。
  • list(n,elem); //构造函数将n个elem拷贝给本身。
  • list(const list &lst); //拷贝构造函数。

代码示例:

void printList(const list<int>& l)
{
	for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
	{
		cout << *it << "  ";
	}
	cout << endl;
}

void test1()
{
	int s = 70;
	list<int> L1;
	L1.push_back(25);
	L1.push_back(26);
	L1.push_back(27);
	L1.push_back(28);
	L1.push_back(29);
	L1.push_back(30);

	cout << "默认构造 L1:" << endl;
	printList(L1); cout << string(s, '-') << endl;
	
	list<int> L2(L1.begin(), L1.end());
	cout << "区间构造 L2:" << endl;
	printList(L2); cout << string(s, '-') << endl;

	list<int> L3(15, 30);
	cout << "n个elem拷贝构造 L3:" << endl;
	printList(L3); cout << string(s, '-') << endl;

	list<int> L4(L3);
	cout << "拷贝构造 L4:" << endl;
	printList(L4); cout << string(s, '-') << endl;
}

在这里插入图片描述

总结: list构造方式同其他几个STL常用容器,熟练掌握即可

3 list 赋值、交换和大小

功能描述: 给list容器进行赋值;交换list容器;对list容器的大小进行操作

函数原型:

  • assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。

  • assign(n, elem); //将n个elem拷贝赋值给本身。

  • list& operator=(const list &lst); //重载等号操作符

  • swap(lst); //将lst与本身的元素互换。

  • size(); //返回容器中元素的个数

  • empty(); //判断容器是否为空

  • resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。

  • resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。

代码示例:

void printList(const list<int>& l)
{
	for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
	{
		cout << *it << "  ";
	}
	cout << endl;
}

//赋值
void test1()
{
	int s = 45;
	list<int> L1;
	L1.push_back(25);
	L1.push_back(26);
	L1.push_back(27);
	L1.push_back(28);
	L1.push_back(29);
	L1.push_back(30);

	cout << "赋值操作" << endl;
	cout << "L1:" << endl;
	printList(L1); cout << string(s, '-') << endl;

	list<int> L2;
	L2 = L1;
	cout << "operator= \tL2:" << endl;
	printList(L2); cout << string(s, '-') << endl;

	list<int> L3;
	L3.assign(10, 25);//10个25
	cout << "assign n个elem\tL3:" << endl;
	printList(L3); cout << string(s, '-') << endl;

	list<int> L4;
	L4.assign(L3.begin(), L3.end());
	cout << "assign 区间\tL4:" << endl;
	printList(L4); cout << string(s, '-') << endl;
}

//交换
void test2()
{
	int s = 45;
	list<int> L1;
	L1.push_back(25);
	L1.push_back(26);
	L1.push_back(27);
	L1.push_back(28);
	L1.push_back(29);
	L1.push_back(30);

	list<int> L2(10, 25);

	cout << endl << "交换操作" << endl << "交换前:" << endl;
	cout << "L1:";
	printList(L1);
	cout << "L2:";
	printList(L2); cout << string(s, '-') << endl;

	cout << "交换后:" << endl;
	L2.swap(L1);
	cout << "L1:";
	printList(L1);
	cout << "L2:";
	printList(L2); cout << string(s, '-') << endl;

}

//判断容器是否为空
void isEmpty(const list<int>& L)
{
	if (L.empty())
	{
		cout << "list容器为空" << endl;
	}
	else
	{
		cout << "list容器不为空,且大小为:" << L.size() << endl;
	}
}

//大小
void test3()
{
	int s = 45;
	list<int> L1;

	list<int> L2(5, 25);

	cout << endl << "大小操作" << endl;
	cout << "L1:";
	printList(L1);
	cout << "L2:";
	printList(L2); cout << string(s, '-') << endl;

	//判断是否为空
	cout << endl << "empty()\t判断是否为空" << endl;
	cout << "L1\t"; isEmpty(L1);
	cout << "L2\t"; isEmpty(L2);
	cout << string(s, '-') << endl;

	//重新制定大小
	cout << endl << "resize()\t重新指定大小" << endl;
	L1.resize(10);
	cout << "默认值0填充\n" << "L1:"; printList(L1);
	L2.resize(10, 30);
	cout << "\n指定值30填充\n" << "L2:"; printList(L2);
	L2.resize(5);
	cout << "\n超出部分删除\n" << "L2:"; printList(L2);
	cout << string(s, '-') << endl;
}

在这里插入图片描述

总结:

  • list赋值和交换操作能够灵活运用即可
  • 判断是否为空 — empty
  • 返回元素个数 — size
  • 重新指定个数 — resize

4 list 插入和删除

功能描述: 对list容器进行数据的插入和删除

函数原型:

  • push_back(elem);//在容器尾部加入一个元素
  • pop_back();//删除容器中最后一个元素
  • push_front(elem);//在容器开头插入一个元素
  • pop_front();//从容器开头移除第一个元素
  • insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。
  • insert(pos,n,elem);//在pos位置插入n个elem数据,无返回值。
  • insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
  • clear();//移除容器的所有数据
  • erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置。
  • erase(pos);//删除pos位置的数据,返回下一个数据的位置。
  • remove(elem);//删除容器中所有与elem值匹配的元素。

代码示例:

void printList(const list<int>& l)
{
	for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
	{
		cout << *it << "  ";
	}
	cout << endl;
}

//两端插入和删除
void test1()
{
	int s = 45;
	list<int> L1;
	L1.push_back(25);
	L1.push_back(26);
	L1.push_back(27);
	L1.push_front(28);
	L1.push_front(29);
	L1.push_front(30);

	cout << "两端插入";
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;

	L1.pop_back();
	cout << "尾删" << endl;
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;

	L1.pop_front();
	cout << "头删" << endl;
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;

	list<int>::iterator it = L1.begin();
	L1.insert(++it, 100);//偏移
	cout << "insert插入单个数据" << endl;
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;

	L1.insert(++it, 3, 200);//再次偏移
	cout << "insert插入多个数据" << endl;
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;

	list<int>::iterator it1 = L1.begin();//指向第一个元素
	L1.erase(++it1);
	cout << "erase删除" << endl;
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;

	L1.remove(200);//把200的数据都移除了
	cout << "remove移除" << endl;
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;

	L1.clear();
	cout << "clear清空" << endl;
	cout << "L1:";
	printList(L1); cout << string(s, '-') << endl;
}

在这里插入图片描述

总结:

  • 尾插 — push_back
  • 尾删 — pop_back
  • 头插 — push_front
  • 头删 — pop_front
  • 插入 — insert 要提供迭代器
  • 删除 — erase 要提供迭代器
  • 移除 — remove 符合指定移除值的数据都移除
  • 清空 — clear
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值