STL(慢慢补充...)

迭代器

迭代器参考博客
(迭代器的作用相当于指针)

y总的stl总结,找个时间把它完整补充一下

C++ STL简介

vector:变长数组,倍增的思想

size()  返回元素个数
empty()  返回是否为空
clear()  清空
front()/back()
push_back()/pop_back()
begin()/end()
[]---当数组使用,和at效果一样
支持比较运算,按字典序--sort

pair<int, int>

first, 第一个元素
second, 第二个元素
支持比较运算,以first为第一关键字,以second为第二关键字(字典序)

string,字符串

size()/length()  返回字符串长度
empty()
clear()
substr(起始下标,(子串长度))  返回子串
c_str()  返回字符串所在字符数组的起始地址,常搭配atof使用
atof将ascII字符串转换为相应的单精度浮点数,比如传入"1.234",经过处理后就返回float类型的数1.234 。类似的还有atoi 、atol、itoa、ftoa等等

queue, 队列

size()
empty()
push()  向队尾插入一个元素
front()  返回队头元素
back()  返回队尾元素   / /重点,老忘掉
pop()  弹出队头元素

priority_queue, 优先队列,默认是大根堆(less)

size()
empty()
push()  插入一个元素
top()  返回堆顶元素
pop()  弹出堆顶元素
定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;

stack, 栈

size()
empty()
push()  向栈顶插入一个元素
top()  返回栈顶元素
pop()  弹出栈顶元素

deque, 双端队列(还没试过)

size()
empty()
clear()
front()/back()
push_back()/pop_back()
push_front()/pop_front()
begin()/end()
[]

set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列

size()
empty()
clear()
begin()/end()
++, -- 返回前驱和后继,时间复杂度 O(logn)

set/multiset
    insert()  插入一个数
    find()  查找一个数
    count()  返回某一个数的个数
    erase()
        (1) 输入是一个数x,删除所有x   O(k + logn)
        (2) 输入一个迭代器,删除这个迭代器
    lower_bound()/upper_bound()
        lower_bound(x)  返回大于等于x的最小的数的迭代器
        upper_bound(x)  返回大于x的最小的数的迭代器
        
map/multimap
    insert()  插入的数是一个pair
    erase()  输入的参数是pair或者迭代器
    find()
    []  注意multimap不支持此操作。 时间复杂度是 O(logn)
    lower_bound()/upper_bound()

unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表
和上面类似,增删改查的时间复杂度是 O(1)
不支持 lower_bound()/upper_bound(), 迭代器的++,–

bitset, 圧位
bitset<10000> s;
~, &, |, ^
>>, <<
==, !=
[]

count()  返回有多少个1

any()  判断是否至少有一个1
none()  判断是否全为0

set()  把所有位置成1
set(k, v)  将第k位变成v
reset()  把所有位变成0
flip()  等价于~
flip(k) 把第k位取反

作者:yxc
链接:https://www.acwing.com/blog/content/404/
来源:AcWing

vector

vector参考博客
vector参考资料

头文件
vector是动态数组,元素的连续存放的,数组的内存空间是可以动态分配的,但是在分配空间的时候往往多分配一些
分配方式:
1.分配新的内存块,它有容器目前容量的几倍。在大部分实现中,vector和string的容量每次以2为因数增长。也就是说,当容器必须扩展时,它们的容量每次翻倍。
2.把所有元素从容器的旧内存拷贝到它的新内存。
3.销毁旧内存中的对象。
4.回收旧内存
(这个问题其实很简单,在调用push_back时,若当前容量已经不能够放入新的元素(capacity=size),那么vector会重新申请一块内存,把之前的内存里的元素拷贝到新的内存当中,然后把push_back的元素拷贝到新的内存中,最后要析构原有的vector并释放原有的内存。所以说这个过程的效率是极低的,为了避免频繁的分配内存,C++每次申请内存都会成倍的增长,例如之前是4,那么重新申请后就是8,以此类推。当然不一定是成倍增长,比如在我的编译器环境下实测是0.5倍增长,之前是4,重新申请后就是6。)

函数总结

1.push_back 在数组的最后添加一个数据
2.pop_back 去掉数组的最后一个数据
3.at 得到编号位置的数据
4.begin 得到数组头的指针
5.end 得到数组的最后一个单元+1的指针
6.front 得到数组头的引用
7.back 得到数组的最后一个单元的引用
8.max_size 得到vector最大可以是多大
9.capacity 当前vector分配的大小
10.size 当前使用数据的大小
11.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
12.reserve 改变当前vecotr所分配空间的大小
13.erase 删除指针指向的数据项
14.clear 清空当前的vector
15.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend 将vector反转构的结束指针返回(其实就是原来的begin-1)
17.empty 判断vector是否为空
18.swap 与另一个vector交换数据

vector的定义和初始化

vector(begin,end):复制[begin,end)区间内另一个数组的元素到vector中
Vector<类型>标识符
Vector<类型>标识符(最大容量)
Vector<类型>标识符(最大容量n,初始所有值x)//前n个为x
vector(const vector&):复制构造函数
Vector< vector< int> >v; 二维向量//这里最外的<>要有空格。否则在比较旧的编译器下无法通过

定义:

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>v1;//定义一个int类型的动态数组
	vector<char>v2;//定义一个char类型的动态数组
	//默认构造动态数组为空
	v1.push_back(1);
	v2.push_back('2');
	cout << v1[0]<<endl;//1
	cout << v2[0] << endl;//2(字符)
	v2.push_back('3');
	vector<char>::iterator p;
	for (p = v2.begin(); p < v2.end(); p++) cout << *p << " ";
	cout << endl;
	for (p = v2.begin(); p != v2.end(); p++) cout << *p << " ";
	cout << endl;
	return 0;
}

1
2
2 3
2 3

初始化:

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>::iterator p;
	vector<int>v1 = { 1,2,3,4 };
	for (p = v1.begin(); p < v1.end(); p++) cout << *p << " ";
	cout << endl;

	vector<int>v2(v1);//v2是v1的一个副本,把v1复制到v2里面(复制要求类型是一样的)
	//完全复制,没有写复制结束的地方就是默认原数组的结尾
	//和v2=v1效果一样
	//vector<int>(v1.begin(),v1.begin()+2);
	for (p = v2.begin(); p < v2.end(); p++) cout << *p << " ";
	cout << endl;

	vector<int>v3(4, 100);//vector<int>v3(n,i),v3包含n个值为i的元素
	for (p = v3.begin(); p < v3.end(); p++) cout << *p << " ";
	cout << endl;

	vector<int>v4(4);//初始值为0
	for (p = v4.begin(); p < v4.end(); p++) cout << *p << " ";
	cout << endl;
 
    vector<string>::iterator p1;
	vector<string>v5(4, "Hi");//vector<int>v3(n,i),v3包含n个值为i的元素
	for (p1 = v5.begin(); p1 < v5.end(); p1++) cout << *p1 << " ";
	cout << endl;
	return 0;
}

1 2 3 4
1 2 3 4
100 100 100 100
0 0 0 0
Hi Hi Hi Hi

初始化-部分复制
vector(begin,end):复制**[begin,end)**区间内另一个数组的元素到vector中
!!切记右边是开区间

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>::iterator p;
	int array[5] = { 10,10,10 };
	vector<int>v = { 2,5,7,8 };

	vector<int>v1(array,array+2);
	//将array从第0位到第二位前面这段区间复制给v1
	for (p = v1.begin(); p < v1.end(); p++) cout << *p << " ";
	cout << endl;

	vector<int>v2(v.begin(), v.begin() + 3);
	for (p = v2.begin(); p < v2.end(); p++) cout << *p << " ";

	return 0;
}

增加,删除元素

增加函数:
void push_back(const T& x):向量尾部增加一个元素X
iterator insert(iterator it,const T& x):向量中迭代器指向元素前增加一个元素x
iterator insert(iterator it,int n,const T& x):向量中迭代器指向元素前增加n个相同的元素x
iterator insert(iterator it,const_iterator first,const_iterator last):向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据

删除函数:
void pop_back():删除向量中最后一个元素
iterator erase(iterator it):删除向量中迭代器指向元素
iterator erase(iterator first,iterator last): 删除向量中[first,last)中元素
void clear():清空向量中所有元素

#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
int main()
{
	vector<int>v(3);
	v[2] = 3;
	v.insert(v.begin() + 2, 4);
	cout << v[0] << endl;
	//初始化每个元素为0
	cout << v[2] << endl;
	//在任意位置前插入元素,插入位置后的元素依次后移
	//insert要求插入的位置是迭代器的位置,不是元素下标
	cout << v[3] << endl;
	return 0;
}

0
4
3

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>::iterator p;
	vector<int>v;
	vector<int>v1 = { 99,100,101 };

	//向量尾部增加一个元素;
	v.push_back(0);
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;
	
	//删除向量尾部最后一个元素
	v.pop_back();
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;

	v.push_back(1);
	v.push_back(2);
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;

	//指定位置单个插入元素
	p = v.begin() + 1;//不用迭代器,直接把v.begin()+1写到函数里面效果一样
	v.insert(p,9);//在第一个元素前添加一个元素
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;
	
	//指定位置单	`个删除
	p = v.begin() + 1;
	v.erase(p);
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;
	
	//指定位置插入另一个数组的区间
	p = v.begin() + 1;
	v.insert(p, v1.begin() + 1, v1.begin() + 3);
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;
	
	//指定位置删除区间
	v.erase(v.begin() + 1, v.begin()+3);
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;
	
	//指定位置连续插入相同元素
	p = v.begin() + 1;
	v.insert(p, 4, 100);
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;
	
	//清空向量中所有的元素
	v.clear();
	for (p = v.begin(); p < v.end(); p++) cout << *p << " ";
	cout << endl;
	cout << "结束";
	return 0;
}

0
空行
1 2
1 9 2
1 2
1 100 101 2
1 2
1 100 100 100 100 2
空行
结束

遍历

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>v = { 99,100,101 };
	//返回pos位置元素的引用
	for (int i = 0; i < v.size(); i++)
		cout << v.at(i) << " ";
	cout << endl;
	//for (int i = 0; i < v.size(); i++)
	//	cout << v[i] << " ";
	//cout << endl;
	//效果一样,但at可以判断操作是否合法,可以防止超出范围
	
	//返回首元素的引用
	cout << v.front()<<endl;
	//返回尾元素的引用
	cout << v.back() << endl;
	//iterator begin():返回向量头指针,指向第一个元素
	//iterator end() :返回向量尾指针,指向向量最后一个元素的下一个位置
	vector<int>::iterator p;
	for (p = v.begin(); p < v.end(); p++) 
		cout << *p << " ";
	cout << endl;
	//reverse_iterator rbegin():反向迭代器,指向最后一个元素
	//reverse_iterator rend() :反向迭代器,指向第一个元素之前的位置
	vector<int>::reverse_iterator pp;
	for (pp = v.rbegin(); pp < v.rend(); pp++)
		cout << *pp << " ";
	cout << endl;
	return 0;
}

99 100 101
99
101
99 100 101
101 100 99

判断数组是否为空

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>v = { 99,100,101 };
	cout << v.empty()<<endl;
	v.clear();//清空
	cout << v.empty();
	return 0;
}

0
1

大小

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>v;
	v.push_back(0);
	v.push_back(1);
	cout << v.size() << endl;
	cout << v.capacity() << endl;
	cout << v.max_size() << endl;
	return 0;
}

2
2
1073741823

交换

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>v1 = { 1,2,3 };
	vector<int>v2 = { 4,5,6 };
	swap(v1, v2);
	for (int i = 0; i < v1.size(); i++)
		cout << v1[i]<<" ";
	cout << endl;
	for (int i = 0; i < v1.size(); i++)
		cout << v2[i] << " ";
	cout << endl;
	return 0;
}

4 5 6
1 2 3

复制

void assign(int n,const T& x):清空向量,设置向量中前n个元素的值为x

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>v1 = { 1,2,3 };
	v1.assign(2, 100);
	for (int i = 0; i < v1.size(); i++)
		cout << v1[i]<<" ";
	
	return 0;
}

100 100

void assign(const_iterator first,const_iterator last):向量中[first,last)中元素设置成当前向量元素

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	vector<int>v1 = { 1,2,3 };
	vector<int>v2 = { 5,6,7 };
	v1.assign(v2.begin(), v2.begin()+1);
	for (int i = 0; i < v1.size(); i++)
		cout << v1[i]<<" ";
	
	return 0;
}

5

二维数组

参考博客

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	//没有初始化的二维数组
	vector<vector<int>>out;
	vector<int>in;
	in.push_back(1);
	in.push_back(2);
	in.push_back(3);
	out.push_back(in);
	in.clear();
	in.push_back(5);
	in.push_back(6);
	in.push_back(7);
	out.push_back(in);
	for (int i = 0; i < out.size(); i++)
	{
		for (int j = 0; j < out[0].size(); j++)
			cout << out[i][j] << " ";
		cout << endl;
	}
	return 0;
}

1 2 3
5 6 7

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	//初始化的二维数组
	vector<vector<int>>out(10,vector<int>(10));
	out[0] = { 1,2,3,5,8 };
	out[1] = { 5,6,7,8,9 };
	cout << out.size()<<endl;
	for (int i = 0; i <out.size(); i++)
	{
		for (int j = 0; j <out[0].size(); j++)
			cout << out[i][j] << " ";
		cout << endl;
	}
	return 0;
}

10
1 2 3 5 8
5 6 7 8 9
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0

#include<iostream>
#include<vector>
#include<cstdio>
using namespace std;
int main()
{
	//没有初始化的二维数组
	vector<vector<int>>out(10,vector<int>(10));
	out = { { 1,2,3,5,8 },{ 5,6,7,8,9 } };
	cout << out.size()<<endl;
	for (int i = 0; i <out.size(); i++)
	{
		for (int j = 0; j <out[0].size(); j++)
			cout << out[i][j] << " ";
		cout << endl;
	}
	return 0;
}

2
1 2 3 5 8
5 6 7 8 9
二维数组两种定义方法(结果一样)
方法一

#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
 
 
int main()
{
    int N=5, M=6; 
    vector<vector<int> > obj(N); //定义二维动态数组大小5行 
    for(int i =0; i< obj.size(); i++)//动态二维数组为5行6列,值全为0 
    { 
        obj[i].resize(M); 
    } 
 
    for(int i=0; i< obj.size(); i++)//输出二维动态数组 
    {
        for(int j=0;j<obj[i].size();j++)
        {
            cout<<obj[i][j]<<" ";
        }
        cout<<"\n";
    }
    return 0;
}

0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0

方法二

#include <string.h>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main()
{
    int N = 5, M = 6;
    vector<vector<int> > obj(N, vector<int>(M)); //定义二维动态数组5行6列 
    for (int i = 0; i < obj.size(); i++)//输出二维动态数组 
    {
        for (int j = 0; j < obj[i].size(); j++)
        {
            cin>>obj[i][j];//1 2 3 4 5 6
        }
        //cout << "\n";
    }
    for (int i = 0; i < obj.size(); i++)//输出二维动态数组 
    {
        for (int j = 0; j < obj[i].size(); j++)
        {
            cout << obj[i][j] << " ";
        }
        cout << "\n";
    }
    return 0;
}

1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6
1 2 3 4 5 6

支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作

排序

reverse 反向排列算法 reverse(v.begin(),v.end())
sort

Pair

对应的头文件是:

#include <utility>

简单介绍:

pair是将2个数据组合成一组数据,当需要这样的需求时就可以使用pair,如stl中的map就是将key和value放在一起来保存。另一个应用是,当一个函数需要返回2个数据的时候,可以选择pair。 pair的实现是一个结构体,主要的两个成员变量是first second 因为是使用struct不是class,所以可以直接使用pair的成员变量。
(原文链接:https://blog.csdn.net/sevenjoin/article/details/81937695)

初始化

#include<iostream>
#include<algorithm>
#include<utility>
using namespace std;
int main()
{
	pair<int, int>ep1;//创建一个空对象,初始化自动赋值0
	cout << ep1.first << " " << ep1.second << endl;
	//0 0
	pair<int, int>p1(1, 1);
	cout << p1.first << " " << p1.second << endl;
	//1 1
	pair<int, string>ep2;
	cout << ep2.first << " " << ep2.second << endl;
	//0  
	pair<int, string>p2(1, "Hello");
	cout << p2.first << " " << p2.second << endl;
	//1 Hello
	pair<int, string>p3(p2);//拷贝构造初始化
	cout << p3.first << " " << p3.second << endl;
	//1 Hello

	//因为pair类型写起来比较繁琐,所以可以用typedef简化声明
	typedef pair<int, int>P;
	P p4(2, 3);
	//pair<int, int> p4 = make_pair(2, 3);  还可以利用make_pair创建新的pair对象:
	cout << p4.first << " " << p4.second << endl;
	//2 3
	P p5 = p4;
	cout << p5.first << " " << p5.second << endl;
	//2 3
	return 0;
}

set

头文件:#include
set 集合容器实现了红黑树(Red-Black Tree)的平衡二叉检索树的数据结构,在插入元素时,它会自动调整二叉树的排列,把该元素放到适当的位置,以确保每个子树根节点的键值大于左子树所有节点的键值,而小于右子树所有节点的键值;另外,还得确保根节点左子树的高度与右子树的高度相等,这样,二叉树的高度最小,从而检索速度最快。要注意的是,它不会重复插入相同键值的元素,而采取忽略处理。
平衡二叉检索树的检索使用中序遍历算法,检索效率高于 vector、deque 和 list 等容器。另外,采用中序遍历算法可将键值由小到大遍历出来,所以,可以理解为平衡二叉检索树在插入元素时,就会自动将元素按键值由小到大的顺序排列。
对于 set 容器中的键值,不可直接去修改。因为如果把容器中的一个键值修改了,set
容器会根据新的键值旋转子树,以保持新的平衡,这样,修改的键值很可能就不在原先那
个位置上了。换句话来说,构造 set 集合的主要目的就是为了快速检索。
multiset(多重集合容器)、map(映照容器)和 multimap(多重映照容器)的内部结
构也是平衡二叉检索树。
使用 set 前,需要在程序的头文件中包含声明“#include ”;set 文件在 C:\Program
Files\Microsoft Visual Studio\VC98\Include 文件夹中,它包含了 set 和 multiset 两种容器的定义。

posted on 2021-02-17 15:28  不依法度  阅读(24)  评论(0)    收藏  举报

导航