STL(list容器)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_42754132/article/details/100058379

3.6 list容器

3.6.1 list容器基本概念

链表是一种物理存储单元上非连续、非顺序的存储结构数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。

相较于vector的连续线性空间,list就显得负责许多,它的好处是每次插入或者删除一个元素,就是配置或者释放一个元素的空间。因此,list对于空间的运用有绝对的精准,一点也不浪费。而且,对于任何位置的元素插入或元素的移除,list永远是常数时间。

List和vector是两个最常被使用的容器。

List容器是一个双向链表。

 

    1. 采用动态存储分配,不会造成内存浪费和溢出
  1. 链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
  2. 链表灵活,但是空间和时间额外耗费较大

3.6.2 list容器的迭代器

List容器不能像vector一样以普通指针作为迭代器,因为其节点不能保证在同一块连续的内存空间上。List迭代器必须有能力指向list的节点,并有能力进行正确的递增、递减、取值、成员存取操作。所谓”list正确的递增,递减、取值、成员取用”是指,递增时指向下一个节点,递减时指向上一个节点,取值时取的是节点的数据值,成员取用时取的是节点的成员。

由于list是一个双向链表,迭代器必须能够具备前移、后移的能力,所以list容器提供的是Bidirectional Iterators.

List有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效。这在vector是不成立的,因为vector的插入操作可能造成记忆体重新配置,导致原有的迭代器全部失效,甚至List元素的删除,也只有被删除的那个元素的迭代器失效,其他迭代器不受任何影响。

3.6.3 list容器的数据结构

list容器不仅是一个双向链表,而且还是一个循环的双向链表。

 

#define _CRT_SECURE_NO_WARNINGS

#include<iostream>

#include<list>

using namespace std;

 

int main(){

 

    list<int> myList;

    for (int i = 0; i < 10; i ++){

        myList.push_back(i);

    }

 

    list<int>::_Nodeptr node =  myList._Myhead->_Next;

 

    for (int i = 0; i < myList._Mysize * 2;i++){

        cout << "Node:" << node->_Myval << endl;

        node = node->_Next;

        if (node == myList._Myhead){

            node = node->_Next;

        }

    }

 

    system("pause");

    return EXIT_SUCCESS;

}

 

3.6.4 list常用API

3.6.4.1 list构造函数

list<T> lstT;//list采用采用模板类实现,对象的默认构造形式:

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

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

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

3.6.4.2 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值匹配的元素。

 

 

3.6.4.3 list大小操作

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

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

resize(num);//重新指定容器的长度为num,

若容器变长,则以默认值填充新位置。

如果容器变短,则末尾超出容器长度的元素被删除。

resize(num, elem);//重新指定容器的长度为num,

若容器变长,则以elem值填充新位置。

如果容器变短,则末尾超出容器长度的元素被删除。

 

3.6.4.4 list赋值操作

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

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

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

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

3.6.4.5 list数据的存取

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

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

3.6.4.6 list反转排序

reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。

sort(); //list排序


07 list
  list 和vector 是最常用的容器
  list是双向循环链表
  赋值 构造 大小 为空 删除 添加 
  移除 remove(10) 删除容器中所有与10匹配的元素
  迭代器不支持随机访问
  反转排序
  reverse 反转
  排序 成员函数 sort
  默认排序 从小到大
  自定义数据类型 ,必须制定排序规则
  高级排序 比如年龄相同按身高排序  则在排序的方法中加入else return.....
  remove自定义数据类型这里有个坑。。。。。。
  VS2019重写了remove()方法 重载==也不能正常调用
  但是g++通过重载==可以正常使用
  remove 删除容器中自定义的数据类型
  所以删除数据的时候最好使用迭代器进行删除
  

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<list>
#include<string>


using namespace std;

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

2 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值匹配的元素。

3 list大小操作
size();//返回容器中元素的个数
empty();//判断容器是否为空
resize(num);//重新指定容器的长度为num,
若容器变长,则以默认值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。
resize(num, elem);//重新指定容器的长度为num,
若容器变长,则以elem值填充新位置。
如果容器变短,则末尾超出容器长度的元素被删除。

4 list赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
list& operator=(const list &lst);//重载等号操作符
swap(lst);//将lst与本身的元素互换。

5 list数据的存取
front();//返回第一个元素。
back();//返回最后一个元素。

6 list反转排序
reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
sort(); //list排序
*/


void test01() {
	/*
	list<int> myList;
	for (int i = 0; i < 10; i++) {
		myList.push_back(i);
	}

	list<int>::_Nodeptr node = myList._Myhead->_Next;

	for (int i = 0; i < myList._Mysize * 2; i++) {
		cout << "Node:" << node->_Myval << endl;
		node = node->_Next;
		if (node == myList._Myhead) {
			node = node->_Next;
		}
	}*/



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

void test02() {

	list<int>L(10, 10);
	list<int>L2 ( L.begin(), L.end());
	L2.push_back(100);
	printList(L);
	

	printList(L2);
	//逆序打印
	for (list<int>::reverse_iterator it = L2.rbegin(); it != L2.rend(); it++) {
		cout << *it << "   ";
	}
	cout << endl;

	//迭代器不支持随机访问
	list<int>::iterator itBegin = L2.begin();
	//itBegin = itBegin + 1;
	//插入数据

	list<int>L3;
	L3.push_back(10);
	L3.push_back(30);
	L3.push_back(20);

	L3.push_front(100);
	L3.push_front(300);
	L3.push_front(200);
    printList(L3);//200 300 100 10 30 20

	//删除两端数据
	L3.pop_front();//头删
	L3.pop_back();//尾删
	printList(L3);

	L3.insert(L3.begin(), 1000);
	printList(L3);
	
	//remove(elem);//删除容器中所有与elem值匹配的元素。
	L3.remove(10);//参数,直接放值
	printList(L3);
}

/*

4 list赋值操作
assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem);//将n个elem拷贝赋值给本身。
list& operator=(const list &lst);//重载等号操作符
swap(lst);//将lst与本身的元素互换。

5 list数据的存取
front();//返回第一个元素。
back();//返回最后一个元素。


*/

void test03() {

	list<int>L3;
	L3.push_back(10);
	L3.push_back(30);
	L3.push_back(20);

	L3.push_front(100);
	L3.push_front(300);
	L3.push_front(200);
	cout << "大小:" << L3.size() << endl;
	if (L3.empty()) {
		cout << "L3为空" << endl;
	}
	else
	{
		cout << "L3不为空!" << endl;

	}
	L3.resize(10);
	printList(L3);

	L3.resize(3);
	printList(L3);

	list<int>L4;
	L4.assign(L3.begin(), L3.end());
	printList(L4);

	cout << "front" << L4.front() << endl;
	cout << "back" << L4.back() << endl;

}


/*
6 list反转排序
reverse();//反转链表,比如lst包含1,3,5元素,运行此方法后,lst就包含5,3,1元素。
sort(); //list排序

*/

//回调函数
bool myCompare(int v1, int v2) {
	return v1 > v2;

}

void test04() {
	list<int>L;
	L.push_back(10);
	L.push_back(20);
	L.push_back(40);
	L.push_back(30);
	L.reverse(); 
	printList(L); // 30 40 20 10

	//sort(L.begin(), L.end());//所有不支持随机访问的迭代器,不可以用系统提供的算法
	//如果不支持用系统提供算法,那么这类内部会提供
	L.sort();//默认从小到大
	printList(L);

	//从大到小
	L.sort(myCompare);
	printList(L);



}



//自定义数据类
class Person
{
  public:
	Person(string name, int age, int stature)
	{
		this->m_name = name;
		this->m_age = age;
		this->m_stature = stature;
	}
	bool operator == (const Person& p)//和自身作对比
	{
		cout << "我被调用了!!!" << endl;
		if (this->m_name == p.m_name && this->m_age == p.m_age && this->m_stature == p.m_stature)
		{
			return true;
		}

		return false;

	}
	
	string m_name;
	int m_age;
	int m_stature;//身高
};

//排序回调函数 
bool personCompare(Person& p1, Person& p2)
{
	/*if (p1.m_age > p2.m_age)
		return true;
	else
		return false;
		*/
	if (p1.m_age == p2.m_age) {
		return p1.m_stature < p2.m_stature;
	}
	else
	{
		return p1.m_age > p2.m_age;
	}
}

//打印数据
void printpreson(list<Person>& L)
{
	for (list<Person>::iterator it = L.begin(); it != L.end(); ++it)
	{
		cout << "姓名:" << it->m_name << " 年龄:" << it->m_age << " 身高:" << it->m_stature << endl;
	}
	
}


void test05()
{
	list<Person>L;
	Person p1("马  云", 45, 160);
	Person p2("马华腾", 47, 178);
	Person p3("周宏伟", 43, 177);
	Person p4("李彦宏", 39, 185);
	Person p5("任正非", 45, 180);
	Person p6("王健林", 45, 170);
	Person p7("王健林", 23, 190);
	L.push_back(p1);
	L.push_back(p2);
	L.push_back(p3);
	L.push_back(p4);
	L.push_back(p5);
	L.push_back(p6);
	
	//需求:打印数据时候,按照年龄的降序,输出


	//反转会改变容器中的数据
	//对于自定义数据类型 必须指定排序规则
	L.sort(personCompare);
   
	//如果年龄相同 按身高升序排序 这就是高级排序
	printpreson(L);//打印数据


	
	
	//删除王健林
	
	//重载== 让remove可以删除自定义的person类型
/*	bool operator == (const Person & p)//和自身作对比
	{
		if (this->m_name == p.m_name && this->m_age == p.m_age && this->m_stature == p.m_stature)
		{
			return true;
		}

		return false;

	}
	*/
	 //L.remove(p6);.//出错:基础数据类型可以直接remove  自定义的不可以
	//重载== 或使用自带的remove方法
    L.remove(p6); //VS2019 重写了 remove代码,直接调用会出错,用g++ 可以通过


	

	cout << "-------------反转前--------------" << endl;
	printpreson(L);//打印数据

	cout << "开始元素 姓名:" << L.front().m_name << " 年龄:" <<
		L.front().m_age << "身高" << L.front().m_stature << endl;
	cout << "最后元素 姓名:" << L.back().m_name << " 年龄:" <<
		L.back().m_age << "身高" << L.back().m_stature << endl;

	cout << "-------------反转后--------------" << endl;
	L.reverse();
	printpreson(L);//打印数据
	cout << "开始元素 姓名:" << L.front().m_name << " 年龄:" <<
		L.front().m_age << "身高" << L.front().m_stature << endl;
	cout << "最后元素 姓名:" << L.back().m_name << " 年龄:" <<
		L.back().m_age << "身高" << L.back().m_stature << endl;



}







int main() {


	
	//test01();
	//test02();
	//test03();
    //test04();

	test05();
	return 0;
}

(本笔记整理自网络资源,侵删)

猜你喜欢

转载自blog.csdn.net/qq_42754132/article/details/100058379