4.1 C++ STL 动态链表容器

c++,stl,动态,链表,容器 · 浏览次数 : 13

小编点评

```c++ #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\", 14, 165); 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;} ```

正文

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;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/5752ce3e.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

与4.1 C++ STL 动态链表容器相似的内容:

4.1 C++ STL 动态链表容器

List和SList都是C++ STL中的容器,都是基于双向链表实现的,可以存储可重复元素的特点。其中,List内部的节点结构包含两个指针一个指向前一个节点,一个指向后一个节点,而SList只有一个指针指向后一个节点,因此相对来说更节省存储空间,但不支持反向遍历,同时也没有List的排序功能。双向链表的数据元素可以通过链表指针串接成逻辑意义上的线性表,不同于采用线性表顺序存储结构的`Vector`

11.1 C++ STL 应用字典与列表

C++ STL 标准模板库提供了丰富的容器和算法,这些模板可以灵活组合使用,以满足不同场景下的需求。本章内容将对前面学习的知识进行总结,并重点讲解如何灵活使用STL中的vector和map容器,以及如何结合不同的算法进行组合。通过灵活组合使用这些容器和算法,能够满足不同场景下的需求,实现高效的数据处理和操作。STL的设计思想是将数据结构和算法进行分离,使得开发者能够更加专注于解决问题,提高了代码的

4.1 C++ Boost 字符串处理库

Boost 库是一个由C/C++语言的开发者创建并更新维护的开源类库,其提供了许多功能强大的程序库和工具,用于开发高质量、可移植、高效的C应用程序。Boost库可以作为标准C库的后备,通常被称为准标准库,是C标准化进程的重要开发引擎之一。使用Boost库可以加速C应用程序的开发过程,提高代码质量和性能,并且可以适用于多种不同的系统平台和编译器。Boost库已被广泛应用于许多不同领域的C++应用程序

4.1 C/C++ 使用结构与指针

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

C++(Qt)-GIS开发-简易瓦片地图下载器

Qt-GIS开发-简易瓦片地图下载器 目录Qt-GIS开发-简易瓦片地图下载器1、概述2、安装openssl3、实现效果4、主要代码4.1 算法函数4.2 瓦片地图下载url拼接4.3 多线程下载5、源码地址6、参考 更多精彩内容 个人内容分类汇总 GIS开发 1、概述 支持单线

C++如何在main函数开始之前(或结束之后)执行一段逻辑?

1. 问题 2. 考察的要点 3. 解决策略 3.1. 方案一:使用GCC的拓展功能 3.2. 方案二:使用全局变量 3.3. 方案三:atexit 4. Demo测试 4.1. 测试代码 4.2. 执行结果 5. 程序异常退出场景 5.1. 存在的问题 5.2. 解决方案 5.2.1. 原理 5.

C#S7.NET实现西门子PLCDB块数据采集的完整步骤

前言 本文介绍了如何使用S7.NET库实现对西门子PLC DB块数据的读写,记录了使用计算机仿真,模拟PLC,自至完成测试的详细流程,并重点介绍了在这个过程中的易错点,供参考。 用到的软件: 1.Windows环境下链路层网络访问的行业标准工具(WinPcap_4_1_3.exe)下载链接:http

.NET周报【1月第4期 2023-01-28】

由于微信公众号排版问题,建议大家在PC端浏览。 国内文章 C# 很少人知道的科技 https://blog.lindexi.com/post/C-%E5%BE%88%E5%B0%91%E4%BA%BA%E7%9F%A5%E9%81%93%E7%9A%84%E7%A7%91%E6%8A%80.html

cmake-4

cmake-4学习,参考 cmake构建c++项目快速入门2-1 cmake构建c++项目快速入门2-2 了解 cmake的工作原理: Windows下用cmake编译cmake (1)先下载cmake(exe) (2)编译源码文件 # -S表示源文件夹下;-B表示新建一个文件夹build,并将编译

[转帖]echo 输出不换行-e \c

http://www.my889.com/i/1952 在shell中,echo输出会自动换行。有时候在循环中不希望echo输出换行。代码实现如下: 1 echo -e " \c" # -e 表示开启转义, \c表示不换行 脚本: 1 2 3 4 5 6 7 8 9 #!/bin/bash i=1