List和SList都是C++ STL中的容器,都是基于双向链表实现的,可以存储可重复元素的特点。其中,List内部的节点结构包含两个指针一个指向前一个节点,一个指向后一个节点,而SList只有一个指针指向后一个节点,因此相对来说更节省存储空间,但不支持反向遍历,同时也没有List的排序功能。

双向链表的数据元素可以通过链表指针串接成逻辑意义上的线性表,不同于采用线性表顺序存储结构的VectorDeque容器,双向链表中任一位置的元素,查找,插入和删除,都具有高效的常数阶算法时间复杂度O(1).

List的缺点是无法通过位置来直接访问序列中的元素,也就是说,不能动态跨段索引元素.为了访问 list 内部的一个元素,必须一个一个地遍历元素,通常从第一个元素或最后一个元素开始遍历。

4.1 双向链表遍历整数

这段代码展示了如何通过访问链表节点的指针来遍历链表中的所有元素。

在代码中,首先创建了一个空链表MyList。然后,使用for循环向链表中插入10个整数数据,每个数据使用push_back()函数插入链表的末尾。

接着,代码定义了一个双向链表节点指针node,将其初始化为第一个节点的下一个节点。注意,第一个节点是链表头,没有实际数据值,因此我们需要将node指针指向第二个节点开始。

然后,代码使用for循环和node指针遍历链表中的所有元素,输出每个节点的数据值。每次输出完一个节点,将node指向下一个节点,判断node是否已经回到了链表头的位置,如果是,则将其指向链表头的第二个节点,即能够实现循环遍历整个链表。

#include <iostream>
#include <list> using namespace std; int main(int argc, char* argv[])
{
list<int> MyList;
// 生成10个测试数据,并链入链表中.
for (int x = 0; x < 10; x++)
MyList.push_back(x); // 将node节点初始化为第一个节点的下一个节点,第一个节点是链表头,无数据.
list<int>::_Nodeptr node = MyList._Myhead->_Next; for (int x = 0; x < MyList._Mysize; x++)
{
cout << "Node: " << node->_Myval << endl;
node = node->_Next; // 每次输出,将node指向下一个链表
if (node == MyList._Myhead) // 如果到头了,直接指向头结点的第二个节点
{
node = node->_Next; // 由于是双向链表,所以到头了会回到起始位置
} // 此时我们执行 node->_Next 继续指向开头
}
system("pause");
return 0;
}

4.2 双向链表遍历结构体

这段代码展示了如何定义结构体、采用自定义的比较函数进行排序,并遍历链表中的所有元素。

在代码中,首先定义了一个结构体Student,包含三个成员变量:name、agecity。然后,创建了一个Student类型的数组stu,数组中有4个元素,每个元素包含一个name、agecity

接着,代码定义了一个空链表MyList,使用push_back()函数把stu数组中的元素按顺序插入链表中。然后还定义了一个MyCompare函数,参数为两个Student类型的引用,返回值为bool类型。MyCompare函数实现了从大到小排序的方法,当s1.age大于s2.age时返回true,否则返回false。

通过调用链表的sort()函数,并传入MyCompare函数来对链表进行排序。在本例中,sort()函数按照从大到小的方式对链表中的元素进行排序。

最后,代码使用for循环和迭代器遍历链表中的所有元素,依次输出每个元素的name、agecity属性。

#include <iostream>
#include <list> using namespace std; struct Student{
char * name;
int age;
char * city;
}; bool MyCompare(Student &s1, Student &s2)
{ // 实现从大到小排序
if (s1.age > s2.age)
return true;
return false;
} int main(int argc, char* argv[])
{
Student stu[] = {
{ "admin", 22, "beijing" },
{ "lisi", 32, "shanghai" },
{ "wangwu", 26, "shandong" },
{"wangermazi",8,"jinan"}
}; list<Student> MyList;
MyList.push_back(stu[0]); // 装入链表数据
MyList.push_back(stu[1]);
MyList.push_back(stu[2]);
MyList.push_back(stu[3]); // 根据Student结构中的age从大到小排序
MyList.sort(MyCompare); // 遍历链表
list<Student>::iterator start, end;
for (start = MyList.begin(); start != MyList.end(); start++)
{
cout << (*start).name << " ";
cout << (*start).age << " ";
cout << (*start).city << endl;
}
system("pause");
return 0;
}

4.3 实现正反向遍历链表

这段代码展示了如何正向和反向遍历链表,其中使用了list容器的begin()、end()、rbegin()rend()函数。

在代码中,首先创建了一个list<int>类型的链表MyList,并使用花括号列表初始化的方式插入了9个整数元素。

然后,采用for循环和迭代器的方式来正向遍历链表MyList中的所有元素,将每个元素依次打印到控制台上。

最后,采用for循环和反向迭代器的方式来反向遍历链表MyList中的所有元素,将每个元素依次反向打印到控制台上。

#include <iostream>
#include <list> using namespace std; int main(int argc, char* argv[])
{
list<int> MyList{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // 正向打印链表元素
for (list<int>::iterator item = MyList.begin(); item != MyList.end(); item++)
cout << *item << endl;
// 反向打印链表元素
for (list<int>::reverse_iterator item = MyList.rbegin(); item != MyList.rend(); item++)
cout << *item << endl;
system("pause");
return 0;
}

4.4 遍历链表中指定元素

这段代码展示了如何定义结构体、构造链表并遍历链表中指定元素的属性。

在代码中,定义了一个Student结构体,有两个成员变量,分别是idname。然后,定义了一个列表MyList,存放Student类型的数据。

接下来,代码定义了一个包含4个元素的Student数组stu,每个元素包含一个id和一个name。然后,使用for循环把stu数组中的元素按照顺序插入链表MyList中。在插入时,每个结构体通过push_back()函数被加入到链表的末尾。

代码使用迭代器遍历MyList链表中的所有元素,查找其中ID为3的元素。如果找到了ID为3的元素,则使用cout语句输出该元素的name属性,否则什么也不做。

#include <iostream>
#include <list>
#include <string> using namespace std; struct Student{
int id;
string name;
}; int main(int argc, char* argv[])
{
list<Student> MyList;
// 定义列表中的元素集合
Student stu[] = {
{ 1,"aaddm"},
{ 2,"admin"},
{ 3,"waann" },
{ 4,"ruiii" }
}; for (int x = 0; x < 4; x++)
{ // 循环插入测试结构 stu[0] - stu[4]
MyList.push_back(stu[x]);
} // 遍历链表中ID=3的元素
list<Student>::iterator start, end;
for (start = MyList.begin(); start != MyList.end(); start++)
{
if ((*start).id == 3) // 寻找ID是3的结构体,找到后输出其name属性
{
cout << "UName: " << (*start).name << endl;
}
}
system("pause");
return 0;
}

4.5 插入/删除链表元素

这段代码展示了如何插入、删除和移除链表中的元素。在代码中,首先创建了一个list<int>类型的链表MyList,并使用大括号列表初始化的方式插入了9个整数元素。

然后,代码连续调用了链表的成员函数push_back()push_front()来向链表的尾部和头部插入一个10和0,使用pop_front()pop_back()来从链表的头部和尾部删除元素。

接着,代码通过调用链表的成员函数insert(),从开头或结尾插入元素,参数为位置迭代器和要插入的数据值。并使用remove()函数移除链表中的元素(这里是7), remove()函数的参数为需要移除的数据。

最后,代码调用了自定义的MyPrint函数打印了修改后的链表元素。

#include <iostream>
#include <list> using namespace std; void MyPrint(list<int> &MyList)
{
list<int>::iterator start, end;
for (start = MyList.begin(); start != MyList.end(); start++)
cout << *start << " ";
cout << endl;
} int main(int argc, char* argv[])
{
list<int> MyList{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; MyList.push_back(10); // 尾部插入数据
MyList.push_front(0); // 头部插入数据 MyList.pop_front(); // 头删数据
MyList.pop_back(); // 尾删除数据 MyList.insert(MyList.begin(), 500); // 从开头插入500
MyList.insert(MyList.end(), 1000); // 从结尾插入1000 MyList.remove(7); // 移除7这个元素
MyPrint(MyList);
system("pause");
return 0;
}

4.6 整数链表正反向排序

这段代码展示了如何对链表进行翻转以及排序,并使用自定义的回调函数来指定排序规则。

在代码中,首先创建了一个list<int>类型的链表MyList,并使用花括号列表初始化的方式插入了10个整数元素。

然后,代码调用了链表的成员函数reverse()来翻转链表。reverse()函数会将链表中的元素顺序全部翻转过来。

接着,代码又调用了链表的成员函数sort()来进行排序。在本例中,使用默认的从小到大排序方式,由sort()函数自动完成。

最后,代码定义了一个MyCompare回调函数,指定了从大到小排序的规则。MyCompare()函数返回值是bool类型,定义了两个参数value1value2,分别表示需要比较的两个数。在本例中,如果value1大于value2,则MyCompare()函数返回true,否则返回false。

代码再次调用了链表的成员函数sort(),这次传入了MyCompare()回调函数作为参数,表示按照从大到小的方式对链表进行排序。

#include <iostream>
#include <list> using namespace std; void MyPrint(list<int> &MyList)
{
list<int>::iterator start, end;
for (start = MyList.begin(); start != MyList.end(); start++)
cout << *start << " ";
cout << endl;
} // 实现的从大到小排序的回调函数
bool MyCompare(int value1, int value2) { return value1 > value2; } int main(int argc, char* argv[])
{
list<int> MyList{ 12,56,33,78,9,43,2,1,7,89 }; MyList.reverse(); // 对链表进行翻转
MyPrint(MyList); MyList.sort(); // 从小到大排序
MyPrint(MyList); MyList.sort(MyCompare); // 从大到小排序
MyPrint(MyList); system("pause");
return 0;
}

4.7 类链表正反向排序

这段C++代码定义了一个Person类,展示了如何对list容器的元素进行排序。

在代码中,Person类定义了三个成员变量,代表人名、年龄和身高。在构造函数中,给这三个成员变量进行了初始化。并创建了一个空的list<Person>类型的MyList变量,使用push_back()函数向其中添加了三个Person类型的数据p1、p2p3

接下来,代码实现了一个MyCompare函数,作为list容器的排序规则。在本例中,MyCompare函数根据年龄和身高进行排序,如果年龄相同,则按照身高由低到高排列,如果年龄不同,则按照年龄由高到低排列。这里的排序规则是根据具体数据类型而定的。

最后使用sort()函数对MyList变量中的元素进行排序,按照自定义的规则对元素排序。并使用迭代器遍历MyList变量,输出其成员的相关信息,以便查看是否已成功对元素进行排序。

#include <iostream>
#include <list>
#include <string> using namespace std; class Person
{
public:
string m_name;
int m_age;
int m_height; public: Person(string name, int age, int height){
this->m_name = name;
this->m_age = age;
this->m_height = height;
}
};
// 排序规则为: 如果年龄相同,则按照身高由低到高排列
bool MyCompare(Person &x,Person &y)
{
if (x.m_age == y.m_age)
return x.m_height < y.m_height; // 身高升序排列
else
return x.m_age > y.m_age; // 年龄降序排列
} int main(int argc, char* argv[])
{
list<Person> MyList; Person p1("a", 20, 169); // 定义元素数据
Person p2("b", 14, 155);
Person p3("c", 14, 165); MyList.push_back(p1); // 加到链表里
MyList.push_back(p2);
MyList.push_back(p3); MyList.sort(MyCompare); // 排序代码 // 排序后进行打印
for (list<Person>::iterator it = MyList.begin(); it != MyList.end(); it++)
cout << "Name: " << it->m_name << " Age: " << it->m_age << " Height: " << it->m_height << endl;
system("pause");
return 0;
}

4.8 类链表成员的删除

这段C++代码展示了list容器的一些基本操作,包括添加元素、删除元素、使用迭代器遍历链表以及运算符重载等。

在代码中,Person类定义了三个成员变量,代表人名、年龄和身高。在构造函数中,为这三个成员变量进行了初始化。代码创建了一个空的list<Person>类型的MyList变量,并使用push_back()函数向其中添加了三个Person类型的数据p1、p2p3

代码使用remove()函数从链表中删除了p3这个Person类型的数据。由于Person类中没有提供运算符的重载,我们需要手动重载运算符,以便remove()函数能够正确地删除链表中自定义的Person类型的结构。在本例中,代码重载了==运算符,使得在删除p3时,remove()函数只删除那些成员m_name、m_agem_height都等于p3的节点。

#include <iostream>
#include <list>
#include <string> using namespace std; class Person
{
public:
string m_name;
int m_age;
int m_height; public: Person(string name, int age, int height){
this->m_name = name;
this->m_age = age;
this->m_height = height;
}
// 重载等于号 == 让 remove() 函数,可以删除自定义的Person类型的结构
public: bool operator==(const Person &p) {
if (this->m_name == p.m_name && this->m_age == p.m_age && this->m_height == p.m_height)
return true;
return false;
}
}; int main(int argc, char* argv[])
{
list<Person> MyList; Person p1("a", 20, 169);
Person p2("b", 14, 155);
Person p3("c", 34, 165); // 初始化并给Person赋值 MyList.push_back(p1); // 将参数放入链表中
MyList.push_back(p2);
MyList.push_back(p3); MyList.remove(p3); // 删除这个类中的p3成员 // 删除p3数据后,通过使用迭代器遍历这个链表,查看情况.
for (list<Person>::iterator it = MyList.begin(); it != MyList.end(); it++)
cout << "Name: " << it->m_name << " Age: " << it->m_age << " Height: " << it->m_height << endl;
system("pause");
return 0;
}

4.1 C++ STL 动态链表容器的更多相关文章

  1. STL序列式容器学习总结

    STL序列式容器学习总结 参考资料:<STL源码剖析> 参考网址: Vector: http://www.cnblogs.com/zhonghuasong/p/5975979.html L ...

  2. STL——序列式容器

    一.容器概述与分类 1. STL容器即是将运用最广的一些数据结构实现出来.常用的数据结构有array, list, tree, stack, queue, hash table, set, map…… ...

  3. C++标准模板库(STL)和容器

    1.什么是标准模板库(STL)? (1)C++标准模板库与C++标准库的关系 C++标准模板库其实属于C++标准库的一部分,C++标准模板库主要是定义了标准模板的定义与声明,而这些模板主要都是 类模板 ...

  4. STL中的容器

    STL中的容器 一. 种类: 标准STL序列容器:vector.string.deque和list. 标准STL关联容器:set.multiset.map和multimap. 非标准序列容器slist ...

  5. STL list链表的用法详解

    本文以List容器为例子,介绍了STL的基本内容,从容器到迭代器,再到普通函数,而且例子丰富,通俗易懂.不失为STL的入门文章,新手不容错过! 0 前言 1 定义一个list 2 使用list的成员函 ...

  6. C++ STL之list容器的基本操作

    由于list和vector同属于序列式容器,有很多相同的地方,而上一篇中已经写了vector,所以这一篇着重写list和vector的不同之处和特有之处. 特别注意的地方: (1)STL中迭代器容器中 ...

  7. 带你深入理解STL之Vector容器

    C++内置了数组的类型,在使用数组的时候,必须指定数组的长度,一旦配置了就不能改变了,通常我们的做法是:尽量配置一个大的空间,以免不够用,这样做的缺点是比较浪费空间,预估空间不当会引起很多不便. ST ...

  8. vc++基础班[28]---动态数组及动态链表的讲解

    C++中也有相应的动态数组.动态链表.映射表的模板类,就是STL中的:vector.list.map 他们属于C++标准中的一部分,对于程序的移植性来说也是不错的,但是在MFC编程中使用 CArray ...

  9. STL中的容器介绍

    STL中的容器主要包括序列容器.关联容器.无序关联容器等. 一]序列容器 (1) vector vector 是数组的一种类表示,提供自动管理内存的功能,除非其他类型容器有更好满足程序的要求,否则,我 ...

  10. [C++]STL中的容器

    C++11 STL中的容器 一.顺序容器: vector:可变大小数组: deque:双端队列: list:双向链表: forward_list:单向链表: array:固定大小数组: string: ...

随机推荐

  1. WPF 实现窗体鼠标事件穿透

    一.窗体变透明,需要加三个属性: AllowsTransparency="True"Background="Transparent"WindowStyle=&q ...

  2. Codeforce:1300B. Assigning to Classes (math)

    解题思路 题目说的意思是,给一个2n个数的数组,注意n为奇数,将这个数组平均分为2份,假设为c1和c2. c1和c2是奇数个元素的数组,比如数组[1,2,3],那么中位数就是2. 那么如何求得中位数差 ...

  3. 【每日一题】28. 模拟战役 (模拟 + DFS/BFS/并查集)

    补题链接:Here 本题属于一道模拟题 虽然这题介绍一大堆,总结起来就是几句话,给出地图n列,前4行是a的地盘,后四行是b的地盘,每个人地盘上面有星号代表大炮. 大炮会 3 * 3的波及周围,会一直传 ...

  4. Codeforces Round #689 (Div. 2, based on Zed Code Competition) 个人题解

    1461A. String Generation void solve() { int n, k; cin >> n >> k; for (int i = 1; i <= ...

  5. 我发现明显产品bug啦

    1.  百度云在下载时,如果选中的文件过多,在点击下载后,不能即时取消所有的下载项! 如下图,点击""全部取消" 出现在列表中项全部消失,但后续新的项继续出现,仍在下载, ...

  6. jmeter+badboy软件安装与使用

    目录: 一.软件下载安装 1.软件下载 2.安装过程 3.安装完成后界面,默认是已经开启录制模式 二.操作使用 1.访问sougou 2.搜索:mrwhite2020 3.选择导出jmx格式 4.使用 ...

  7. 腾讯视频客户端 MP4 下载

    腾讯视频直接使用客户端下载视频,得到的是 QLV 文件,这种加密视频文件只能通过腾讯视频客户端播放.最新版的腾讯客户端下载的 QLV 文件,使用各种转码软件都不能正常转码.从服务器下载的 TS 文件一 ...

  8. 机器学习-线性回归-损失函数+正则化regularization-06

    目录 1. 为什么要加上正则项 2 L1稀疏 L2平滑 3. 代码1--L2正则 4 代码2--L2正则2 5. 代码3--l1正则 6. ElasticNet 1. 为什么要加上正则项 防止模型的过 ...

  9. Java求一个集合的所有子集

    转载请注明出处: 求一个集合的所有子集表示从一个集合当中,任取任意项或不取,所能得到的所有结果,比如有一个集合{a,b,c,d},那么{a,b}, {b, d}等都是它的子集,空集也是它的子集, 一个 ...

  10. C语言中的操作符:了解与实践

    ​ 欢迎大家来到贝蒂大讲堂 ​ 养成好习惯,先赞后看哦~ ​ 所属专栏:C语言学习 ​ 贝蒂的主页:Betty's blog 1. 操作符的分类 操作符又叫运算符,它在C语言中起着非常大的作用,以下是 ...