面向对象程序设计之链表 list 的简析(C++)

2024-09-02 23:36

本文主要是介绍面向对象程序设计之链表 list 的简析(C++),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介:链表是一个双向的结构,与string与vector不同的是他不支持[]访问,因为链表是由一个节点一个节点连接而成的,并不连续。我们可以在常数量级内对于链表进行插入与删除数据

1.构造函数

我们在cplusplus.com中可以查到链表总共有四种构造的方式:1.无参构造(默认构造);2.使用n个val构造;3.迭代器区间构造;4.拷贝构造

接下来让我们简单创建一个链表并对其进行遍历 

//n个val构造
list<int> lt(5, 1);
//迭代器遍历
list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

2.迭代器的简要了解

2.1按照功能分类

iterator:迭代器

reverse_iterator:反向迭代器

const iterator:只读迭代器

const reverse_iterator:只读反向迭代器

2.2按照性质分类 

单向迭代器:forward_list/unordered_map/unorder_set......只支持 ++ 操作

双向迭代器:list/map/set........支持 ++ 、-- 操作

随机迭代器:string/vector/deque.........支持 ++ 、-- 、+ 、-  操作

还有两种迭代器可以作为了解,他们就是只读与只写迭代器,根据箭头各种迭代器之间可以近似理解为包含关系,即若一个函数参数要求单项迭代器,那么双向迭代器的参数同样可以,但是反之则不可以

 比如如果我们使用不匹配的迭代器就有可能出错,例如库函数中的sort要求随机迭代器,因为其底层函数需要进行 - 的操作,如果是双向迭代器就无法进行该操作,就会报错 

list<int> lt(5, 1);
sort(lt.begin(), lt.end());//错误,库函数中的sort要求使用随机迭代器类型

 

3.常用接口以及注意事项 

3.1push_back

尾插函数,注意push_back只能插入单个数据,无法直接插入(1,1)这样类型的函数

//n个val构造
list<int> lt(5, 1);lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
//迭代器遍历
list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

3.2emplace_back

尾插函数,与push_back不同的是,emplace_back可以直接插入(2,2)这样的数据

struct A
{
public:A(int a1 = 1,int a2 = 1):_a1(a1),_a2(a2){}int _a1;int _a2;};list<A> lt;
A aa1(1, 1);
lt.push_back(aa1);
lt.push_back(A(2, 2));//匿名对象
//lt.push_back(2, 2);//报错lt.emplace_back(aa1);
lt.emplace_back(A(2, 2));
lt.emplace_back(2, 2);//可以直接尾插//迭代器遍历
list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

 3.3insert

在指定位置之前插入数据,可以使用循环实现在任意位置插入数据

list<int> lt(5, 1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);lt.insert(lt.begin(), 10);//在首位前插入数据//在第k个位置之前插入数据
auto it = lt.begin();
int k = 3;
while (k--)
{it++;
}
lt.insert(it, 30);//迭代器遍历
list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

3.4erase 

删除指定位置数据

list<int> lt(5, 1);lt.push_back(2);lt.push_back(3);lt.push_back(4);lt.push_back(5);int x = 0;cin >> x;auto it = find(lt.begin(), lt.end(), x);//如果find没有找到就会返回第二个参数也就是lt.end()while (it != lt.end()){lt.erase(it);}//迭代器遍历
list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

3.5reverse 

逆置链表

list<int> lt(5, 1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);lt.reverse();//迭代器遍历
list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

 3.6sort

库函数中的sort函数不支持链表,所以链表自实现了一个sort函数来进行排序,默认是升序,可以使用仿函数来进行降序的调整即lt.sort(greater<int>())与lt.sort(less<int>())

list<int> lt(5, 1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);lt.sort();//迭代器遍历
list<int>::iterator it = lt.begin();
while (it != lt.end())
{cout << *it << " ";++it;
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

3.7merge

将两个有序链表进行合并,如果将second链表合并到first链表,则second链表就会置空,其合并的原理就是取小尾插到被合并链表

list<int> first;
first.push_back(1);
first.push_back(2);
first.push_back(3);
first.push_back(4);list<int> second;
second.push_back(10);
second.push_back(20);
second.push_back(30);
second.push_back(40);first.merge(second);
//范围for遍历
for (auto e : first)
{cout << e << " ";
}
cout << endl;
//范围for遍历
for (auto e : second)
{cout << e << " ";
}
cout << endl;

3.8unique

去重,注意只能对有序数据去重 

list<int> lt(5, 1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;lt.unique();//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

3.9splice

剪切另一链表的指定数据到被粘贴链表,被剪切链表中被剪切的数据会直接删除,也可以对自身进行操作,即变化自身链表数据的顺序

list<int> first;
first.push_back(1);
first.push_back(2);
first.push_back(3);
first.push_back(4);list<int> second;
second.push_back(10);
second.push_back(20);
second.push_back(30);
second.push_back(40);auto it = first.begin();
it++;first.splice(it, second);//在First链表的第一个位置之后粘贴剪切后的数据
//范围for遍历
for (auto e : first)
{cout << e << " ";
}
cout << endl;
//范围for遍历
for (auto e : second)
{cout << e << " ";
}
cout << endl;list<int> lt(5, 1);
lt.push_back(2);
lt.push_back(3);
lt.push_back(4);
lt.push_back(5);
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;int k = 0;
cin >> k;
auto it = find(lt.begin(), lt.end(), k);
if(it != lt.end())
{lt.splice(lt.begin(), lt, it);
}
cout << endl;
//范围for遍历
for (auto e : lt)
{cout << e << " ";
}
cout << endl;

 

 

这篇关于面向对象程序设计之链表 list 的简析(C++)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131389

相关文章

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

csu1329(双向链表)

题意:给n个盒子,编号为1到n,四个操作:1、将x盒子移到y的左边;2、将x盒子移到y的右边;3、交换x和y盒子的位置;4、将所有的盒子反过来放。 思路分析:用双向链表解决。每个操作的时间复杂度为O(1),用数组来模拟链表,下面的代码是参考刘老师的标程写的。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名