C++ list的使用
list定义
List是stl实现的双向链表,与向量(vector)相比, 它允许快速的插入和删除,但是随机访问却比较慢。
使用时需要添加头文件#include
list<int>lst1; //创建空list
list<int> lst2(5); //创建含有5个元素的list
list<int>lst3(3,1); //创建含有1个元素的list
list<int>lst4(lst2); //使用lst2初始化lst4
list<int>lst5(lst2.begin(),lst2.end()); //同lst4
list常用方法
Lst1.assign() 给list赋值
Lst1.back() 返回最后一个元素
Lst1.begin() 返回指向第一个元素的迭代器
Lst1.clear() 删除所有元素
Lst1.empty() 如果list是空的则返回true
Lst1.end() 返回末尾的迭代器
Lst1.erase() 删除一个元素
Lst1.front() 返回第一个元素
Lst1.insert() 插入一个元素到list中
Lst1.merge() 合并两个list
Lst1.pop_back() 删除最后一个元素
Lst1.pop_front() 删除第一个元素
Lst1.push_back() 在list的末尾添加一个元素
Lst1.push_front() 在list的头部添加一个元素
Lst1.remove() 从list删除元素
Lst1.reverse() 把list的元素倒转
Lst1.size() 返回list中的元素个数
Lst1.sort() 给list排序
Lst1.unique() 删除list中重复的元素
下面是用得相对较少的:
Lst1.get_allocator() 返回list的配置器
Lst1.max_size() 返回list能容纳的最大元素数量
Lst1.rbegin() 返回指向第一个元素的逆向迭代器
Lst1.remove_if() 按指定条件删除元素
Lst1.rend() 指向list末尾的逆向迭代器
Lst1.resize() 改变list的大小
Lst1.splice() 合并两个list
Lst1.swap() 交换两个list
假如定义了list myList;
myList.push_front(1); //前面插入元素1
myList.push_back(2); //后面插入元素2
//遍历
typedef list<int>::iterator Iter;
Iter itBegin = myList.begin();
Iter itEnd = myList.end();
for (; itBegin != itEnd; ++itBegin)
printf(" %d", *itBegin);
//最原始的遍历
for ( list<int>::iterator it = myList.begin(); it != myList.end(); it++ ) {
cout << *it << ' ';
}
迭代器的用法和指针有些像,可以用*运算符访问内部的元素,
++和--运算符可以将它后移或前移一位,用==和!=运算符进判断两个迭代器所指的位置是否一致。
但要注意:list的迭代器不支持it += x或it1 - it2这样的运算,也不支持<,<=等运算符。
begin()成员函数返回指向头部元素的迭代器。
end()成员函数返回指向末尾位置的迭代器。这个“末尾位置”指的是最后一个元素再往后一位,
也就是说end()所指的位置不包含有效元素,它相当于一个虚设的节点。
Iter it = myList.end();
--it;
//C++11中可以直接写成it = prev(myList.end());
//这里prev是头文件<iterator>提供的函数,用于返回将某个迭代器前移一位的结果
Iter it2 = myList.insert(it, 3);
//myList的内容:1,3,2
这段代码首先定义了一个迭代器it,然后在end()的基础上左移一位,让它指向链表中最后一个元素。
insert(it, val)成员函数用于在链表中插入元素。it为该链表的一个迭代器,val为待插入的值,
插入后val位于it所指位置的前一位。返回值为一个迭代器,表示val插入到了哪个位置。
insert(it,6) : ↓
插入后it的位置是不变的, insert成功后会返回插入元素的位置的迭代器!!!
来个题目玩玩:(洛谷的题目)
题目描述
一个学校里老师要将班上N个同学排成一列,同学被编号为1∼N,他采取如下的方法:
- 先将1号同学安排进队列,这时队列中只有他一个人;
- 2−N号同学依次入列,编号为i的同学入列方式为:老师指定编号为i的同学站在编号为1∼(i−1)中某位同学(即之前已经入列的同学)的左边或右边;
- 从队列中去掉M(M<N)个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第1行为一个正整数N,表示了有N个同学。
第2−N行,第i行包含两个整数k,p,其中k为小于i的正整数,p为0或者1。若p为0,则表示将i号同学插入到k号同学的左边,p为1则表示插入到右边。
第N+1行为一个正整数M,表示去掉的同学数目。
接下来M行,每行一个正整数x,表示将x号同学从队列中移去,如果x号同学已经不在队列中则忽略这一条指令。
输出格式
1行,包含最多N个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入 #1
4 1 0 2 1 1 0 2 3 3
输出 #1
2 4 1
样例解释:
将同学2插入至同学1左边,此时队列为:
21
将同学3插入至同学2右边,此时队列为:
231
将同学4插入至同学1左边,此时队列为:
2341
将同学3从队列中移出,此时队列为:
241
同学3已经不在队列中,忽略最后一条指令
最终队列:
241
#include <iostream>
#include <cstdio>
#include <list>
using namespace std;
const int N = 1e5+5;
//给list<int>::iterator来个别名,太长了
typedef list<int>::iterator Iter;
//队列
list<int> myque;
/*
插入的话需要知道插入的位置,
这里用一个数组把所有位置给存起来,
这样插入的话就不用循环去找了
*/
Iter pos[N];
//查看删了没有的
bool book[N];
int n, m;
int main()
{
scanf("%d", &n);
myque.push_front(1);
pos[1] = myque.begin();
//插入
int no, lr;//插入到第no号同学的左或右
for ( int i = 2; i <= n; ++i ) {
scanf("%d %d", &no, &lr);
//右边
if ( lr ) {
Iter temp = pos[no];
temp++;//插入的是右边,所以加加
pos[i] = myque.insert(temp, i);
}
//左边
else {
pos[i] = myque.insert(pos[no], i);
}
}
//删除同学
scanf("%d", &m);
for ( int i = 1; i <= m; ++i ) {
scanf("%d", &no);
//如果没有删过,那就删
if ( !book[no] ) {
myque.erase(pos[no]);
//myque.remove(no);超时!!!!!!
book[no] = true;//标记为删过了
}
}
//打印出来
for ( Iter it = myque.begin(); it != myque.end(); it++ ) {
printf("%d ", *it);
}
return 0;
}