悲剧的文本-STL链表详解

STL链表详解

1.基础操作

定义

list<int>l;//定义一个int类型的链表
list<int>l={......}//定义一个含有......元素的链表
list<int>l(n);//定义一个长度为n并且全部初始化为0的int型的链表
list<int>l(n,m);//定义一个长度为n并且全部初始化为m的int型的链表

插入

l.push_front();//在l的前面插入一个数据
l.push_back();//在l的后面插入一个数据
l.emplace();//在l的某个位置插入某个数据
l.emplace_front();//在l的前面插入一个数据,但是更快
l.emplace_back();//在l的后面插入一个数据,但是更快

查找

l.front();//l的第一个元素
l.back();//l的最后一个元素
l.empty();//判断l是否为空
l.size();//l的大小

删除

l.clear();//清空l
l.pop_front();//删除l的第一个元素
l.pop_back();//删除l的最后一个元素
l.remove();//删除l的指定元素(值)
l.erase();//删除l的指定元素(迭代器)
l.erase(first,last);//删除l的指定区间的元素,first,last是迭代器,不包括last
l.remove_if();//按条件删除元素

修改

l.reverse();//倒转l

其他

l.begin();//返回l第一个元素的迭代器
l.end();//返回l最后一个元素的后一个的迭代器
l.sort();//给l排序
l.rbegin();//返回l最后一个元素的迭代器(相当于l.begin()的逆操作)
l.rend();//返回l第一个元素的前一个元素的迭代器(相当于l.end()的逆操作)
l.swap();//交换两个链表
l.splice();//合并两个链表,合并后第2个为空
l.merge();//合并两个有序的链表,并保持新链表有序

具体代码实现

#include<bits/stdc++.h>
using namespace std;
int main() {
	list<int>l {1,2,3,4,5};
	//auto关键字是可以根据后面变量的值来自动确定数据类型,C++11之后有用(应该吧
	auto first=l.begin();
	auto last=l.end();
	/*
	first为第一个元素的迭代器
	last为最后一个元素的迭代器
	其类型为int指针
	*/
	cout<<*first<<' '<<*last;//"1 5"输出第一个和最后一个元素 (*first为解引用,表示指针对应的值)
	printf("\n");
	l.push_front(0);//在l开头添加一个0
	l.push_back(6);//在l末尾添加一个6
	for(auto p=l.begin(); p!=l.end(); p++) { //从开头遍历到结尾,注意l.end()是最后一个元素的后一个位置,所以是!=l.end();
		cout<<*p<<' ';
	}
	//"0 1 2 3 4 5 6"
	printf("\n");
	auto it=l.begin();
	it++;//表示第二个位置
	l.emplace(it,1);//在第二个位置插入1
	for(auto p=l.begin(); p!=l.end(); p++) { //从开头遍历到结尾,注意l.end()是最后一个元素的后一个位置,所以是!=l.end();
		cout<<*p<<' ';
	}
	//"0 1 1 2 3 4 5 6"
	printf("\n");
	l.remove(0);//删除0
	for(auto p=l.begin(); p!=l.end(); p++) { //从开头遍历到结尾,注意l.end()是最后一个元素的后一个位置,所以是!=l.end();
		cout<<*p<<' ';
	}
	printf("\n");
	auto first1=l.begin();
	auto last1=l.end();
	first1++;//第二个元素
	last1--;//倒数第一个元素
	l.erase(first1,last1);//删除第二个到倒数第二个(链表的函数的末迭代器都不包括本身)
	for(auto p=l.begin(); p!=l.end(); p++) { //从开头遍历到结尾,注意l.end()是最后一个元素的后一个位置,所以是!=l.end();
		cout<<*p<<' ';
	}
	//"1 6"
	printf("\n");
	printf("%d %d",l.front(),l.back());
	//"1 6"
	return 0;
}

2.迭代器

什么是迭代器

在看了刚刚的代码后,相信大家都会发现“迭代器”这个词语反复出现,它是什么意思呢?我们不妨先想一想静态链表。

在静态链表中我们一般会用两个数组存储(如下图)

image-20230321202338064

其中的“指针域”就可以理解为迭代器,它是指向下一个数据的指针,如这个链表

image-20230321202548664

其中l.begin()就是nex[0] l.end()就是nex[5]

怎么表示迭代器

在基本操作的一下函数中,有许多的参数都需要迭代器,那么我们又该如何表示?

image-20230321202909017

STL链表是动态双向链表,所以迭代器在表示时,我们需要用指针来表示

指针的基本概念

指针是一个地址,指向一个数据,一般在定义时需要在原本的数据后加一个'*'

int * p

指针的输出

指针是一个地址,所以不能直接输出,我们要找到它指向的数据,就需要一个操作,这个操作就叫“解引用”

int a=13;
int * p=&a;
printf("%d",*p);
//13

了解了指针我们就可以用变量表示迭代器了

具体的定义可以用一个关键字auto表示

auto关键字是可以根据后面变量的值来自动确定数据类型,C++11之后有用(应该吧

list<int>l{1,2,3};
auto p=l.begin();
printf("%d",*p);
//1

实际应用

例:悲剧的文本

你有一个破损的键盘。键盘上所有的键都能正常工作,但有时Home键或者End键会自动按下(注意:按下home键光标会跳到一行的开头,按下end键,光标会跳到一行的结尾。你并不知道键盘存在这一问题,而是专心地打稿子,甚至连屏幕都没有打开。当你打开显示器之后,展现在你面前的是一段悲剧的文本。你的任务是打开显示器之前计算出这段悲剧的文本。

输入

包括多组数据。每组数据一行,包含不超过100000个字母、下划线、字符“[”或者“]”。其中字符“[”表示HOME键,“]”表示END键。输入结束标志为文件结束符EOF。

输出

每输入一行,对应输出的一行,即屏幕上的悲剧文本。

样例

样例输入1

This_is_a_[Beiju]_text
[[]][][]Happy_Birthday_to_Tsinghua_University

样例输出1

BeijuThis_is_a__text
Happy_Birthday_to_Tsinghua_University

\(Code\)

#include<bits/stdc++.h>
using namespace std;
list<char> l;
string s;
int main() {
   auto it=l.begin();//默认指向开头
   while(cin>>s) {
   	for(int i=0; i<s.size(); i++) {
   		if(s[i]=='[') {
   			it=l.begin();//遇到'['时指向开头
   		} else if(s[i]==']') {
   			it=l.end();//遇到']'时指向结尾
   		} else {
   			l.emplace(it,s[i]);//在 it 指向的位置(开头/结尾)插入
   		}
   	}
//		for(auto p=l.begin(); p!=l.end(); p++) {
//			printf("%c",*p);
//		}错误代码,改了好久 T^T(新定义指针的会溢出)
   	for(it=l.begin();it!=l.end();it++){
   		printf("%c",*it);
   	}
   	l.clear();
   	printf("\n");
   }
   return 0;
}
posted @ 2023-08-21 16:02  Li_Feiy  阅读(84)  评论(2)    收藏  举报