这段时间刷leetcode发现自己对很多常用的类很不熟悉,有时某些操作忘记了还要到网上去找,很多博客整理的很不全,这里我做个小结,也方便自己以后查阅。
一、常用类
这里主要介绍几个在leetcode中经常用到的类:
- vector
- string
- set
- map
- queue
- stack
使用之前都要声明各自的头文件,并使用std域名,如果不使用std域名,则每次定义变量之前要在使用的类之前加上域名std。
(一)vector
大小可变的数组,支持快速随机访问,在尾部插入或者删除元素速度很快,其余位置的插入或者删除较慢。
声明:
vector<template> v_name;
这里的template需要替换:
- 某种特定的数据类型,比如:int、double、long等。
- 也可以是自己定义的结构体
- 也可以是某些类,比如:vector、queue等。
1、push_back
vector<int> nums;
nums.push_back(1);
将数据存放到vector的末尾,vector的长度+1。
2、pop_back
括号内不需要参数
删除数组的末尾元素,没有返回值(void)
vector<int> nums;
nums.push_back(1);
nums.pop_back();
3、erase
这个操作有2种使用方法:
- 删除单独的某个元素
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
nums.erase(nums.begin() + 10);
注意,这里必须使用迭代器与偏移的形式来指明需要删除的元素。
上面的例子中,删除nums[10]也就是数组中的第11个元素,而不是第10个。
- 批量删除连续的元素
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
nums.erase(nums.begin(), nums.begin() + 10);
批量删除也需要写成迭代器与偏移的形式。
这个例子中删除nums[0]到nums[10]之间的所有元素,包括nums[0],但是不包括nums[10],一共是10个元素,这里顺便说一下大部分的区间规则都是左闭右开的。
4、insert
这个操作有3种用法:
(1)插入单个元素
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
int j = 10;
nums.insert(nums.begin() + 2, j);
将j元素插入到nums[2]的位置,nums[2]原来的元素移动到nums[3],依次类推。
(2)批量插入多个相同元素
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
nums.insert(nums.begin() + 2, 6, 100);
三个参数:
- 迭代器,指定插入的第一个位置
- 整数,指定插入元素的数量
- 需要插入的data
上面的例子,从nums[2]的位置开始,插入6个100。
(3)从其他同类型的vector中,批量插入元素
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
vector<int> temp;
for(int i=30; i < 40; i++)
temp.push_back(i);
int j = 10;
nums.insert(nums.begin() + 2, temp.begin(), temp.begin() + 7);
三个参数:
- 迭代器,指定插入的第一个位置
- 迭代器,选定批量元素的起始位置
- 迭代器,选定批量元素的结束位置(不包括这个迭代器)
这个例子中,插入的是30~36(不包括temp.begin() + 7),共计7个元素。
这里也是左闭右开
5、使用algorithm头文件实现常用操作
(1)sort
排序操作
这个操作需要algorithm头文件,可升序可降序,一般用于数字和字符串排序。
- 升序
#include<vector>
#include<algorithm>
using namespace std;
vector<int> nums;
for(int i=20; i >= 0; i--)
nums.push_back(i);
sort(nums.begin(), nums.end());
- 降序
使用反向迭代器就能实现降序排序了
反向迭代器,正如其名:
rbegin() = end()
rend() = begin()
#include<vector>
#include<algorithm>
using namespace std;
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
sort(nums.rbegin(), nums.rend());
另外,你们可能也注意到了,凡是使用到了迭代器的地方,都可以加偏移来实现vector内部分排序,比如:
sort(nums.begin() + 1, nums.begin() + 10);
注:我在网上看过很多写比较函数,来实现结构体或者类排序的,但是我写出来的VSCode没有报错,一运行就出问题,找不出原因。如果有知道怎么写的大神,欢迎在评论区指明。
(2)find
查找操作
#include<vector>
#include<algorithm>
using namespace std;
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
auto n = find(nums.begin(), nums.end(), 5);
三个参数:
- 迭代器,查找的起始位置
- 迭代器,查找的终止位置(不在查找范围内)
- 需要查找的数据
返回:
找到了,则返回找到元素的迭代器
没有找到,返回第二个迭代器(即:查找的终止位置)
注:很多时候,如果不知道要返回什么,直接写auto,可以自动匹配数据类型。
(3)reverse
反转vector,这个有时候会用,自己动手写也很快
vector<int> nums;
for(int i=0; i < 20; i++)
nums.push_back(i);
reverse(nums.begin(), nums.end());
也可以部分反转,改一改迭代器就行。
(二)string
与vector相似的容器,但专门用于保存字符。
基础:
- 字符串声明:
string s1(); // si = ""
string s2("Hello"); // s2 = "Hello"
string s3(4, 'K'); // s3 = "KKKK"
string s4("12345", 1, 3); //s4 = "234",即 "12345" 的从下标 1 开始,长度为 3 的子串
- 字符串赋值:
可以用 char* 类型的变量、常量,以及 char 类型的变量、常量对 string 对象进行赋值。
string s5, s6;
s5 = "Hello"; // s5 = "Hello"
s6 = 'K'; // s6 = "K”
- 字符串连接
string s7 = s5 + s6; //s7 = "HelloK"
或者:
string s8("123"), s9("abc");
s8.append(s9); // s8 = "123abc"
s8.append(s9, 1, 2); // s8 = "123abcbc"
s8.append(3, 'K'); // s8 = "123abcbcKKK"
s8.append("ABCDE", 2, 3); // s8 = "123abcbcKKKCDE",添加 "ABCDE" 的子串(2, 3):"CDE"
- 字符串修改
string s7 = s5 + s6; //s7 = "HelloK"
s7[0] = 'w'; //s7 = "welloK"
1、compare
除了可以用 <、<=、==、!=、>=、> 运算符比较 string 对象外,string 类还有 compare 成员函数,可用于比较字符串。
compare 成员函数有以下返回值:
- 小于 0 表示当前的字符串小;
- 等于 0 表示两个字符串相等;
- 大于 0 表示另一个字符串小。
string s1("hello"), s2("hello, world");
int n = s1.compare(s2); // 比较s1与s2
n = s1.compare(1, 2, s2, 0, 3); // 比较s1的子串 (1,2) 和s2的子串 (0,3)
n = s1.compare(0, 2, s2); // 比较s1的子串 (0,2) 和 s2
n = s1.compare("Hello"); // 比较s1与“Hello”
n = s1.compare(1, 2, "Hello"); //比较 s1 的子串(1,2)和"Hello”
n = s1.compare(1, 2, "Hello", 1, 2); //比较 s1 的子串(1,2)和 "Hello" 的子串(1,2)
compare操作实际上是将两个字符串逐个字符的ASCII值相减,直到出现第一个不为0的字符或者其中一个字符串结束(注:当字符串结束后,之后的字符的ASCII视为0)
2、substr
求 string 对象的子串。
string s1 = "this is ok";
string s2 = s1.substr(2, 4); // s2 = "is i": s1[2]('i')开始往后的4个字符组成的字符串
s2 = s1.substr(2); // s2 = "is is ok":s1[2]('i')开始往后直到结束的字符组成的字符串
3、swap
交换两个字符串的内容。
string s1("West"), s2("East"); // s1 = "West",s2 = "East"
s1.swap(s2); // s1 = "East",s2 = "West"
错误的写法:
s1.swap("hello");
4、查找操作
string 类有一些查找子串和字符的成员函数。
- 它们的返回值都是子串或字符在 string 对象字符串中的位置(即下标)。
- 如果查不到,则返回 string::npos。
string: :npos 是在 string 类中定义的一个静态常量。这些函数如下:
(1)find
从前往后查找子串或字符出现的位置。
- 查找字符
string s1("Source Code");
int n;
if ((n = s1.find('u')) != string::npos)
//查找 u 出现的位置
cout << "1: " << n << "," << s1.substr(n) << endl;
//输出 1: 2,urce Code
- 指定查找的开始位置
string s1("Source Code");
int n;
if ((n = s1.find("Source", 3)) == string::npos)
//从下标3开始查找"Source",找不到
cout << "2: " << "Not Found" << endl;
//输出 2: Not Found
- 查找字符串
string s1("Source Code");
int n;
if ((n = s1.find("Co")) != string::npos)
//查找子串"Co"。能找到,返回"Co"的位置
cout << "3: " << n << ", " << s1.substr(n) << endl;
//输出 3: 7, Code
(2)rfind
从后往前查找子串或字符出现的位置。
string s1("Source Code");
int n;
if ((n = s1.rfind('u')) != string::npos)
//查找 u 出现的位置
cout << "1: " << n << "," << s1.substr(n) << endl;
//输出 1: 2,urce Code
(3)find_first_of
从前往后查找何处出现另一个字符串中包含的字符(可以指定开始查找的位置)。
string s1("Source Code");
int n;
if ((n = s1.find_first_of("ceo")) != string::npos)
//查找第一次出现或 'c'、'e'或'o'的位置
cout << "4: " << n << ", " << s1.substr(n) << endl;
//输出 4: l, ource Code
(4)find_last_of
从后往前查找何处出现另一个字符串中包含的字符(可以指定开始查找的位置)。
string s1("Source Code");
int n;
if ((n = s1.find_last_of('e')) != string::npos)
//查找最后一个 'e' 的位置
cout << "5: " << n << ", " << s1.substr(n) << endl;
//输出 5: 10, e
(5)find_first_not_of
从前往后查找何处出现另一个字符串中没有包含的字符(可以指定开始查找的位置)。
string s1("Source Code");
int n;
if ((n = s1.find_first_not_of("eou", 1)) != string::npos)
// 从下标1开始查找第一次出现非 'e'、'o' 或 'u' 字符的位置
cout << "6: " << n << ", " << s1.substr(n) << endl;
//输出 6: 3, rce Code
(6)find_last_not_of
从后往前查找何处出现另一个字符串中没有包含的字符(可以指定开始查找的位置)。
string s1("Source Code");
int n;
if ((n = s1.find_last_not_of("eou", 1)) != string::npos)
//从下标1开始查找第一次出现非 'e'、'o' 或 'u' 字符的位置
cout << "6: " << n << ", " << s1.substr(n) << endl;
//输出 6: 0, Source Code
5、erase
删除指定位置的字符或者字符串
string s1("Real Steel");
s1.erase(1, 3); //删除子串(1, 3)“eal”,此后 s1 = "R Steel"
s1.erase(5); //删除下标5及其后面的所有字符,此后 s1 = "R Ste"
6、insert
insert 成员函数可以在 string 对象中插入另一个字符串,返回值为对象自身的引用。
string s1("Limitless"), s2("00");
s1.insert(2, "123"); //在下标 2 处(s1[2]='m')插入字符串"123",s1 = "Li123mitless"
s1.insert(3, s2); //在下标 3 处(s1[3]='2')插入 s2 , s1 = "Li10023mitless"
s1.insert(3, 5, 'X'); //在下标 3 处(s1[3]='0')插入 5 个 'X',s1 = "Li1XXXXX0023mitless"
(三)set
set是使用红黑树实现的一个容器,具有自动去重的功能。
1、insert
set<int> list;
for(int i=0; i < 10; i++)
list.insert(i);
2、erase
删除操作,这个操作根据里面的key value来决定删除哪一个元素(set与vector不同,本身没有顺序)
set<int> list;
for(int i=0; i < 100; i++)
list.insert(i);
list.erase(5);
3、count
统计其中某一key value的数量,因为set具有自动去重的功能,所以返回值要么是0,要么是1.
set<int> list;
for(int i=0; i < 100; i++)
list.insert(i);
list.count(5);
4、lower_bound(val)
返回某个key value不小于val的迭代器,通过*来访问该key value
set<int> list;
for(int i=0; i < 100; i++)
list.insert(i);
auto temp = list.lower_bound(5);
cout << *temp;
// 输出: 5
5、upper_bound(val)
返回某个key value大于val的迭代器,通过*来访问该key value
set<int> list;
for(int i=0; i < 100; i++)
list.insert(i);
auto temp = list.upper_bound(5);
cout << *temp;
// 输出: 6
6、clear
删除set里面的所有数据
(四)map
映射,这是一个很有用的容器。
声明
map<template1, template2> name;
通过映射可以将两种不同或相同的数据联系起来
比如:将字符串映射为数字
map<string, int> str2int;
1、insert
map<string, int> str2int;
str2int.insert(map<string, int>::value_type("hello", 5));
cout << str2int["hello"];
// 输出 5
注意:不能重复映射。
举个例子:
map<string, int> str2int;
str2int.insert(map<string, int>::value_type("hello", 5));
str2int.insert(map<string, int>::value_type("hello", 50));
cout << str2int["hello"];
// 输出 5
这里输出的还是5,不是50,如果要修改映射为50,则:
str2int["hello"] = 50;
2、count
查找其中某个key value出现的次数,并返回该次数,由于不能重复映射,最多为1
map<string, int> str2int;
str2int.insert(map<string, int>::value_type("hello", 5));
cout << str2int.count("hello");
3、find
查找函数,找出某个key value,并返回该迭代器
map<string, int> str2int;
str2int.insert(map<string, int>::value_type("hello", 5));
auto f = str2int.find("hello");
cout << f->first << " " << f->second;
// 输出 hello 5
4、erase
删除,有两种方法:
- 按迭代器删除
map<string, int> str2int;
str2int.insert(map<string, int>::value_type("hello", 5));
auto f = str2int.find("hello");
str2int.erase(f);
- 按key value删除
map<string, int> str2int;
str2int.insert(map<string, int>::value_type("hello", 5));
auto f = str2int.find("hello");
str2int.erase("hello");
5、lower_bound(val)
返回 key value >= val 的第一个位置
map<int, string> int2str;
int2str.insert(map<int, string>::value_type(5, "hello"));
auto f = int2str.lower_bound(5);
cout<< f->first << " " << f->second;
// 输出: 5 hello
6、upper_bound(val)
返回 key value >= val 的第一个位置
map<int, string> int2str;
int2str.insert(map<int, string>::value_type(5, "hello"));
auto f = int2str.lower_bound(9);
if(f == int2str.end())
cout << "not found";
else
cout<< f->first << " " << f->second;
// 输出 not found