STL之List容器

一、list容器的基本概念

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

链表(list)是一种物理存储单元上非连续的存储结构(存储的地址是非连续的),数据元素的逻辑顺序是通过链表中的指针链接来实现

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

节点的组成:一个存储数据元素的数据域,另一个储存下一个结点的指针域

STL中的链表是一个双向循环链表

 

由于链表的存储方式不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。

list的优点:

      1、采用动态存储分配,不会造成内存浪费和溢出

      2、链表实行插入和删除操作十分方便,修改指针即可,不需要移动大量的元素

list的缺点:

      1、链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大

list有一个重要性质,插入操作和删除操作不会造成原有list迭代器的失效,这个在vector中不成立的。

二、List构造函数

学习目标:学会创建list容器

函数原型:

      list<T> lst;                       //list采用模板类实例化对象。默认构造形式

      list(beg,end);                  //构造函数将[beg,end)区间的元素拷贝给本身

      list(n,elem);                   //构造函数将n个elem拷贝给本身

      list(const list &lst);        //拷贝构造函数

示例: 

#include "iostream"
#include <list>

using namespace std;
void PrintList02(const list<int> &L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void testList02() {
	//1、创建list容器的对象 默认构造形式
	list<int> lst1;
	lst1.push_back(10);
	lst1.push_back(20);
	lst1.push_back(30);
	lst1.push_front(40);

	//遍历List容器
	PrintList02(lst1);

	//2、区间拷贝
	list<int> l2(lst1.begin(),lst1.end());
	PrintList02(l2);

	//3.n个elem拷贝
	list<int> l3(10, 100);
	PrintList02(l3);

	//4、拷贝构造函数
	list<int> l4(l3);
	PrintList02(l4);

}
int main()
{
	testList02();
	system("pause");
	return 0;
}

三、list容器的赋值与交换

学习目标:给list容器进行赋值,以及交换list容器

函数原型:

      assign(beg,end);                            //将某一容器的[beg,end)区间中的数据拷贝赋值给本身

      assign(n,elem);                             //将n个elem拷贝给本身

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

      swap(lst);                                     //将lst与本身互换

 示例:

#include "iostream"
#include <list>

using namespace std;
void PrintList03(const list<int> &L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void testList03()
{
	list<int> L1;
	L1.push_front(40);
	L1.push_front(30);
	L1.push_front(20);
	L1.push_front(10);
	PrintList03(L1);
	//1、区间赋值操作
	list<int> L2(L1.begin(), L1.end());
	PrintList03(L2);
	//2、重载等号操作符
	list<int> L3;
	L3 = L2;
	PrintList03(L3);
	//3、n个elem赋值
	list<int> L4(10, 66);
	cout << "L4与L5互换前:" << endl;
	PrintList03(L4);

	//4、list容器互换
	list<int> L5(5,55);
	PrintList03(L5);
	cout << "L4与L5互换后:" << endl;
	L4.swap(L5);
	PrintList03(L4);
	PrintList03(L5);
}
int main()
{
	testList03();
	system("pause");
	return 0;
}

 四、list容器的大小操作

学习目标:对list容器的大小进行操作

函数原型:

      size();

      empty();

      resize(num);

      resize(n,elem);

示例:

#include "iostream"
#include <list>
using namespace std;
void PrintList04(const list<int> &L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void testList04()
{
	list<int> L1;
	L1.push_front(40);
	L1.push_front(30);
	L1.push_front(20);
	L1.push_front(10);
	PrintList04(L1);
	//1、resize(elem)
	L1.resize(10);
	PrintList04(L1);
	//2、resize(n,elem)
	L1.resize(15, 66);
	PrintList04(L1);
	//3、判断是否为空
	while (!L1.empty())
	{
		if (!L1.empty())
		{
			L1.pop_back();
			cout << "容器中的元素个数:" << L1.size() << endl;
			PrintList04(L1);
		}
		else
		{
			cout << "容器为空!" << endl;
		}
	}
}
int main()
{
	testList04();
	system("pause");
	return 0;
}

 五、list容器的插入与删除

学习目标:对list容器进行数据的插入与删除

函数原型:

      push_back(elem);                    //在容器尾部加一个元素

      push_front(elem);                   //在容器头部加一个元素

      pop_front();                            //删除容器的第一个元素

      pop_back();                           //删除容器的最后一个元素

      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位置的数据,返回下一个数据的位置

      erase(elem);                      //删除容器中所有与elem值匹配的数据

示例:

#include "iostream"
#include <list>
using namespace std;
void PrintList05(const list<int> &L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void listtest05()
{
	list<int>  L1;
	L1.push_back(30);
	L1.push_back(40);
	L1.push_front(20);
	L1.push_front(10);
	PrintList05(L1);

	//1、insert(pos,elem)  pos为迭代器
	L1.insert(L1.begin(),1000);
	PrintList05(L1);

	//2、insert(pos,n,elem)  pos为迭代器
	L1.insert(L1.begin(), 3, 666);
	PrintList05(L1);

	list<int>::iterator it = L1.begin();
	it++;
	list<int>::iterator itend = L1.end();
	itend--;
	//3、insert(pos,beg,end)
	L1.insert(it, it, itend);
	PrintList05(L1);

	//4、erase(beg,end)
	L1.erase(it, itend);
	PrintList05(L1);

	//5、erase(pos)
	list<int>::iterator it1 = L1.begin();
	L1.erase(it1);
	PrintList05(L1);

	//6、remove(elem)
	L1.remove(666);
	PrintList05(L1);

	//clear();
	L1.clear();
	PrintList05(L1);
}
int main()
{
	listtest05();
	system("pause");
	return 0;
}

 六、list数据存取

学习目标:能灵活的对list容器中的数据进行存取操作

注意:list容器不支持随机迭代器,因为链表中数据的存取不是在一段连续的内存空间中。所以不能使用下标[]索引和at方式访问链表中的数据

函数原型:

      front();                      //返回第一个元素

     back();                      //返回最后一个元素

 示例:

#include "iostream"
#include <list>

using namespace std;
void PrintList28(const list<int> &L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
void listTest28()
{
	list<int> L1;
	for (int i = 0; i < 5; i++)
	{
		L1.push_back(i);
	}
	for (int i = 10; i > 5; i--)
	{
		L1.push_front(i);
	}
	PrintList28(L1);

	//L1[0];    代码报错,不支持下标[]方式访问
	//L1.at(0); 代码报错,不支持at方式访问
	//原因:list本质是链表,不是用连续性的空间存储数据,迭代器也不支持随机访问
	list<int>::iterator it = L1.begin();
	it++;
	it--;          //不报错,说明list容器支持双向迭代器
	//it=it + 3;   报错,list容器的迭代器不能跳跃式访问,所以不是随机迭代器
	cout << "第一个元素为:" << L1.front() << endl;
	cout << "最后一个元素为:" << L1.back() << endl;
}
int main()
{
	listTest28();
	system("pause");
	return 0;
}

七、list容器的反转与排序

学习目标:对list容器中的元素进行反转,以及将容器中的数据进行排序

函数原型:

      reverse();                    //反转链表

      sort();                            //链表排序 

示例: 

#include "iostream"
#include <list>
using namespace std;
void PrintList29(const list<int> &L)
{
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
}
bool MyCompare(int v1, int v2) {
	return v1 > v2;
}
void ListTest29()
{
	list<int> L1;
	for (int i = 10; i > 0; i--)
	{
		L1.push_back(i);
	}
	cout << "反转之前:" << endl;
	PrintList29(L1);
	//1、反转
	cout << "反转之后:" << endl;
	L1.reverse();
	PrintList29(L1);
	list<int> L2(L1);
	cout << "L2的拷贝构造结果" << endl;
	PrintList29(L2);
	L2.reverse();
	cout << "L2反转:" << endl;
	PrintList29(L2);
	//2、排序 默认是从小到大 升序
	L2.sort();
	cout << "L2排序:" << endl;
	PrintList29(L2);

	//3、所有不支持随机访问迭代器的容器,不可以使用标准算法
	//sort(L1.begin(), L1.end());
	//L2的降序排列
	L2.sort(MyCompare);
	cout << "L2使用仿函数降序:" << endl;
	PrintList29(L2);

}
int main()
{
	ListTest29();
	system("pause");
	return 0;
}

总结:反转 reverse()

          排序 sort(仿函数)

八、list排序案例

案例描述:将person自定义数据类型进行排序,Person中属性有姓名、年龄、身高

排序规则:按照年龄进行升序,如果年龄相同,按照身高进行降序

示例:

#include "iostream"
#include <list>
#include <string>

using namespace std;
class Person
{
public:
	Person(string name, int age, int height)
	{
		this->m_Name = name;
		this->m_Age = age;
		this->m_Height = height;
	}
	string m_Name;
	int m_Age;
	int m_Height;
};
int a = 1;
bool PsCompare(Person &p1, Person &p2)
{
	if (a == 1)
	{
		if (p1.m_Age == p2.m_Age)
		{
			return p1.m_Height > p2.m_Height;
		}
		else
		{
			return p1.m_Age > p2.m_Age;
		}
	}
	else
	{
		if (p1.m_Age == p2.m_Age)
		{
			return p1.m_Height < p2.m_Height;
		}
		else
		{
			return p1.m_Age < p2.m_Age;
		}
	}
	
}
void PrintList30(const list<Person> &P)
{
	for (list<Person>::const_iterator it = P.begin(); it != P.end(); it++)
	{
		cout << "姓名:" << it->m_Name << " " << "年龄:" << it->m_Age << " " << "身高:" << it->m_Height << endl;
	}
}
void ListTest30()
{
	list<Person> LP;
	Person p1("小兰", 20, 170);
	Person p2("小红", 20, 160);
	Person p3("小明", 12, 164);
	Person p4("小花", 23, 180);
	Person p5("小绿", 18, 170);
	LP.push_back(p1);
	LP.push_back(p2);
	LP.push_back(p3);
	LP.push_back(p4);
	LP.push_back(p5);
	cout << "排序前:" << endl;
	PrintList30(LP);
	cout << "降序排序后:" << endl;
	LP.sort(PsCompare);
	PrintList30(LP);

}
int main()
{
	ListTest30();
	system("pause");
	return 0;
}

总结:对于自定义数据类型,必须指定排序规则,否则编译器不知道该如何排序

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值