【C++第三阶段】list容器排序

ops/2024/9/24 19:14:10/

以下内容仅为当前认识,可能有不足之处,欢迎讨论!


文章目录

  • 构造函数
  • 赋值和交换
  • 大小操作
  • 插入和删除
  • 数据存取
  • 反转和排序
  • 排序案例


image-20240411211821277

list容器在STL中是双向循环链表。

如图所示,每一个节点三个域,前向指针域,后向指针域,数据域。前向指针域指向前一个结点的地址,后向指针域指向后一个结点的地址,数据与存放该结点数据。第一个结点的前向指针指向最后一个结点的地址;最后一个结点的后向指针指向第一个结点的地址。

但是值得注意的是,插入删除操作不会造成list迭代器的失效,而迭代器在vector中是一次性的。

list优点:

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

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

list缺点:

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

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

总结:STL中list和vector是两个最常使用的容器,各有优缺点。

构造函数

目的函数
默认构造形式list<T> lst;
将[beg,end)区间中的元素拷贝给本身list(beg,end);
构造函数将n个elem拷贝给本身list(n,elem);
拷贝构造函数list(const list &lst);

示例代码:

void test0419a() {list<int> lst;lst.push_back(10);lst.push_back(20);lst.push_back(30);lst.push_back(40);print(lst);cout << "区间元素拷贝给本身" << endl;list<int> lst2(++lst.begin(), lst.end());print(lst2);cout << "构造函数将n个elem拷贝给本身" << endl;list<int> lst3(3, 6);print(lst3);cout << "拷贝构造函数" << endl;list<int> lst4 = lst2;print(lst4);
}

运行结果:

image-20240428205708289

赋值和交换

赋值和交换,说的是list容器中,给list容器进行赋值,以及交换list容器。

目的函数原型
将区间内的数据赋值给本身assign(begin,end);
将n个elem拷贝赋值给本身assign(n,elem);
重载等号操作符list& operator=(const list &lst);
将lst与本身的元素互换swap(lst);

示例代码:

void test0428a() {list<int> lst;for (int i = 10; i < 14; i++) {lst.push_back(i*2/3+1);lst.push_front(i * 3 / 2-1);}cout << "lst为↓" << endl;print(lst);list<int> lst2;lst2.assign(lst.begin(), lst.end());cout << "lst2为↓" << endl;print(lst2);list<int> lst3;lst3 = lst;cout << "lst3为↓" << endl;print(lst3);list<int> lst4;cout << "lst4为↓" << endl;lst4.assign(10, 100);print(lst4);swap(lst3, lst4);cout << "lst3为↓" << endl;print(lst3);cout << "lst4为↓" << endl;print(lst4);}

运行结果:

image-20240428211919091

大小操作

目的:对容器的大小进行操作

目的函数
返回容器中元素个数size()
判断容器是否为空empty()
重新制定容器长度,后长度若长于原长度,则以默认值填充,后长度若短于原长度,则截断。resize(num)
以指定值填充。resize(num,elem)

示例代码:

void test0429a() {list<int> lst;for (int i = 1; i < 4; i++) {lst.push_back(i * 2 - 3);lst.push_front(i * 3 - 2);}cout << "lst当前为:";print(lst);cout << "lst的元素个数:" << lst.size() << "." << endl;cout << "lst是空list容器吗?" << endl;if (lst.empty()) {cout << "lst是空容器。" << endl;}else {cout << "lst不是空容器。" << endl;}cout << "重新lst裁剪大小为4个" << endl;lst.resize(4);print(lst);cout << "扩充lst为7个,以7填充。" << endl;lst.resize(7, 7);print(lst);
}

运行结果:

image-20240429094748862

插入和删除

目的:对list容器进行数据的插入和删除。

目的函数
容器尾部添加一个元素push_back(elem)
删除容器最后一个元素pop_back()
容器开头添加一个元素push_front(elem)
删除容器最后一个元素pop_front()
在pos位置插入elem元素的拷贝,返回新数据的位置insert(pos,elem)
在pos位置插入n个elem数据, 不需要返回值insert(pos,n,elem)
在pos位置插入[begin,end)区间的数据,没有返回值insert(pos,begin,end)
删除容器中所有数据clear()
删除[begin,end)区间的数据,返回下一个数据的位置。erase(begin,end)
删除pos位置的数据,返回下一个数据的位置erase(pos)
删除容器中所有值为elem的元素remove(elem)

示例代码:

void test0429b() {list<int> lst;list<int> tsl;for (int i = 0; i < 4; i++) {lst.push_back(i * 2 - 5);lst.push_front(i * 5 - 2);tsl.push_back(i);}cout << "lst当前为↓" << endl;print(lst);cout << "删除lst头部第一个元素后,lst↓" << endl;lst.pop_front();print(lst);cout << "删除lst尾部最后一个元素后,lst↓" << endl;lst.pop_back();print(lst);list<int> ::iterator begin = lst.begin();cout << "在第2个位置插入1个3" << endl;lst.insert(++begin, 3);print(lst);cout << "在第3个位置插入4个2" << endl;lst.insert(++begin, 4, 2);print(lst);cout << "lst当前为↓" << endl;print(lst);cout << "tsl当前为↓" << endl;print(tsl);cout << "lst尾部插入tsl后,lst为↓" << endl;lst.insert(lst.end(), tsl.begin(), tsl.end());print(lst);cout << "lst删除第一个元素的位置,返回下一个数据的位置为" << endl;lst.erase(lst.begin());print(lst);cout << "此时begin的位置对应的元素是" << *begin << endl;cout << "lst删除第begin+1个到最后一个元素的数据后,为↓" << endl;lst.erase(++begin, lst.end());print(lst);}

运行结果:

image-20240429102550302

数据存取

目的:对list容器中数据进行存取

目的函数
返回第一个元素值front()
返回最后一个元素值back()

示例代码:

void test0429c() {list<int> lst;for (int i = -2; i < 3; i++) {lst.push_back(i * 2 - 2);}print(lst);cout << "第一个元素值为:" << lst.front() << endl;cout << "最后一个元素值为:" << lst.back() << endl;}

运行结果:

image-20240429103149556

list不可以用[]访问容器中的元素,也不可以用at()方式访问容器中的元素。

因为list是链表,不是用连续线性空间存储数据,迭代器也是不支持随机访问的。

反转和排序

目的:①反转list容器内元素;②对list容器进行排序。

反转可以直接用容器内方法,排序

所有不支持随机访问迭代器的容器,不可以用标准算法。

所以,要想对这些容器进行排序,可以使用内部提供的对应算法。

排序默认是升序,如果是降序,则需要写一个对应函数。

示例代码:

void test0429d() {list<int> lst;for (int i = -2; i < 3; i++) {lst.push_back(i * 2 - 2);lst.push_front(i * i - 2);}cout << "now lst -->"<<endl;print(lst);cout << endl;cout << "after reverse,the lst ==" << endl;lst.reverse();print(lst);cout << endl;cout << "after sort ,lst == " << endl;lst.sort();print(lst);cout << endl;cout << "now sort by function compare , lst == " << endl;lst.sort(compare<int>);print(lst);cout << endl;
}

运行结果:

image-20240429105248422

排序案例

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

规则:按照年龄进行升序(默认),如果年龄相同,则按照身高进行降序。

疑问:怎么通过某一个属性进行排序?

看视频解决:通过自定义的排序函数。

示例代码:

#include<iostream>#include<string>using namespace std;#include<list>template<typename T>
void print(list<T>& lst) {for (typename list<T>::iterator lst_front = lst.begin(); lst_front != lst.end(); ++lst_front) {cout << *lst_front;//cout << "  ";}cout << endl;
}class Person {
public:Person() {};Person(string name, int age, double height) :person_name(name), person_age(age), person_height(height) {};
public:string person_name;int person_age;double person_height;
};ostream& operator<<(ostream& out, Person& person) {cout << person.person_name << "年龄为:" << person.person_age << ",\t身高为:" << person.person_height << "." << endl;//在实现operator<<时,最好不要直接使用cout,而应该使用传递给函数的ostream对象out,这可以提高代码的可复用性。——GPT4return out;
}//template <typename Person>
bool person_compare(const Person& per, const Person& son) {if (per.person_age == son.person_age) {return per.person_height > son.person_height;}return son.person_age > per.person_age;
}void test0429e() {Person person[5];Person One("大道", 20, 1.85);person[0] = One;Person Two("两极", 19, 1.83);person[1] = Two;Person Three("三眼", 22, 1.84);person[2] = Three;Person Four("四象", 22, 1.86);person[3] = Four;Person Five("五行", 24, 1.88);person[4] = Five;list<Person> lst_ps;for (int i = 0; i < (sizeof(person) / sizeof(person[0])); i++) {lst_ps.push_back(person[i]);}cout << "Person 排序前" << endl;print(lst_ps);cout << "Person 排序后" << endl;lst_ps.sort(person_compare);print(lst_ps);}int main() {test0429e();system("pause");return 0;
}

运行结果:

image-20240429115426985


以上是我的学习笔记,希望对你有所帮助!
如有不当之处欢迎指出!谢谢!

学吧,学无止境,太深了


http://www.ppmy.cn/ops/28987.html

相关文章

【c++】----STL简介string

目录 1. 什么是STL 2. STL的版本 3. STL的六大组件 4.STL的缺陷 5.string类 1. 为什么学习string类&#xff1f; 6.string类的常用接口说明&#xff08;下面我们只讲解最常用的接口&#xff09; 1.string 常见构造 2.string类的遍历 iterator 迭代器遍历 &#xff08;…

揭秘靠信息差搞钱的三个步骤!

互联网时代&#xff0c;所有搞钱的底层逻辑&#xff0c;就是信息差。谁能把信息差玩透&#xff0c;链接好供应链与需求链&#xff0c;谁就可以赚钱。 旅游卡批发这么赚钱&#xff0c;为什么很多人不愿意做&#xff1f;因为懒人太多&#xff0c;总想坐等收益。昨天我在常被割韭…

Spring Cloud原理详解

Spring Cloud原理详解 一、引言 随着云计算和微服务架构的兴起&#xff0c;Spring Cloud作为一套完整的微服务解决方案&#xff0c;受到了广大开发者的青睐。它基于Spring Boot&#xff0c;通过提供一系列的服务治理功能&#xff0c;帮助开发者快速构建稳定、可扩展的微服务应…

学习100个Unity Shader (15) ---透明+双面渲染

文章目录 效果shader理解参考 效果 shader Shader "Example/AlphaBlendBothSided" {Properties{_Color ("Main Tint", Color) (1, 1, 1, 1)_MainTex ("Texture", 2D) "white" {}_AlphaScale ("Alpha Scale", Range(0, 1)…

【EXCEL自动化11】pandas提取指定数据(补充)

🔥学好办公自动化,帮你节省更多宝贵的时间 🔥这个专栏收录python办公自动化的实操案例,利用python实现高效的办公自动化 🔥实现excel,word,文件批处理等自动化操作 目录 一、批量提取多个文件的指定数据二、批量读取xlsx文件并另存三、批量替换文件夹中所有excel文件…

Linux下启动jenkins报错问题解决

jenkins端口报错 java.io.IOException: Failed to start Jettyat winstone.Launcher.<init>(Launcher.java:209)at winstone.Launcher.main(Launcher.java:496)at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at java.base/jdk.int…

嵌入式Linux 系统组成

三种系统组成图 嵌入式Linux系统和PC完整的操作系统的对比如下&#xff1a; // 可以看到我们嵌入式arm 上的 u-boot 同时替代了 BIOS 和 grub2&#xff08;bootmgr&#xff09;的功能 &#xff0c;下面我们来进行一些详细的介绍 1. BIOS和UEFI的作用&#xff1a; a. 进行硬件自…

android 修改最低亮度值,不要太暗

/frameworks/base/core/java/com/android/internal/display/BrightnessSynchronizer.java 修改最低亮度&#xff0c;不能太暗看不见 /** * Converts between the int brightness system and the float brightness system. */ public static float brightnessInt…