欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++标准库(PAT算法笔记)

程序员文章站 2022-07-12 13:53:42
...

C++标准库 (PAT算法笔记)

1. Vecotr 变长数组

1.1 vector定义

vector<typename> name;

vector<int> name;
vector<double> name;
vector<node> name;     //结构体

vector<vector<int> > name;   //> > 之间要加空格
//可以当作两个维都可变长的二维数组

vector<int> vi[100];   //其中一维已经固定,另一维可变长

1.2 vector容器内元素的访问

//通过下标访问
vi[index];

//通过迭代器访问
vector<int>::iterator it;
vector<double>::iterator it;
//迭代器可以理解为一种类似指针的东西

//可以通过*it来访问vector里的元素
#include <stdio.h>
#include <vector>

using namespaced std;

int main(){
    vector<int> vi;
    for(int i = 1; i <= 5; i++){
        vi.push_back(i);  //循环完毕后,vi中元素为1 2 3 4 5
    }
    //vi.begin()为取vi的首元素地址,而it指向这个地址
    vector<int>::iterator it = vi.begin();
    for(int i = 0; i < 5; i++){
        printf("%d ", *(it + i));    //输出vi[i]
    }
    return 0;
}

//这里可以看出vi[i] 和 *(vi.begin()+i) 是等价的

//begin()函数取vi的首元素地址,end()函数取尾元素地址的下一个地址
//end()作为迭代器末尾标志,不储存任何元素

//另一种遍历vector中元素的写法
#include <stdio.h>
#include <vector>

using namespace std;

int main(){
    vector<int> vi;
    for(int i = 0; i <= 5; i++){
        vi.push_back(i);
    }
    //vector的迭代器不支持it < vi.end()的写法
    //循环条件只能用it != vi.end()
    for(vector<int>::iterator it = vi.begin(); it != vi.end(); it++){
        printf("%d ", *it);
    }
    return 0;
}

//在常用STL容器中,只有vector和string中,才允许使用vi.begin()+i这种写法

1.3 vector常用函数

//push_back()
//在vector后面添加一个元素, 时间复杂度为O(1)
vi.push_back(x);

//pop_back()
//用以删除vector的尾元素,时间复杂度为O(1)
vi.pop_back(x);

//size()
//用来获取vector中元素的个数,时间复杂度为O(1)
vi.size();

//clear()
//用来清空vector中的所有元素,时间复杂度为O(N),N为vector中元素的个数
vi.clear();

//insert()
//用来向vector的任意迭代器it处插入一个元素x, 时间复杂度为O(N)
vi.insert(it, x);

#include <stdio.h>
#include <vector>

using namespace std;

int main(){
    vector<int> vi;
    for(int i = 1; i <= 5; i++){
        vi.push_back(i);
    }
    //1 2 3 4 5
    vi.insert(vi.begin() + 2, -1);   //将-1插入vi[2]的位置
    for(int i = 0; i < vi.size(); i++){
        printf("%d ", vi[i]);
        //1 2 -1 3 4 5
    }
}

//erase()
//1.删除单个元素
vi.erase(vi.begin()+3);

//2.删除一个区间内的所有元素
//erase(first, last)删除[first, last)内的所有元素
vi.erase(vi.begin() + 1, vi.begin() + 4);   //删除vi[1] vi[2] vi[3]
//删除vector内所有元素可以用vi.erase(vi.begin(), vi.end())

1.4 vector常见用途

  1. 本身可以用作数组使用,在元素个数不确定的场合可以节省空间
  2. 使用vector实现邻接表

2. Set 集合

set是一个内部有序且不含重复元素的容器

2.1 set的定义

set<typename> name;

set<int> name;
set<node> name;

set<typename> Arrayname[arraySize];
set<int> a[100];

2.2 set容器内元素的访问

//set只能通过迭代器访问
set<typename>::iterator it;
set<char>::iterator it;

//不支持*(it+i)的访问方式
//只能按如下方式枚举
#include <stdio.h>
#include <set>

using namespace std;

int main(){
    set<int> st;
    st.insert(3);
    st.insert(5);
    st.insert(2);
    st,insert(3);
    for(set<int>::iterator it = st.begin(); it != st.end();it++){
        printf("%d ", *it);
    }
    return 0;
}

2.3 set常用函数

//insert()
//可将x插入set容器中,并自动递增排序和去重,时间复杂度O(logN).

//find()
//find(value)返回set中对应值为value的迭代器,时间复杂度为O(logN)
set<int>::iterator it = st.find(2);
printf("%d\n", *it);
//or
printf("%d\n", *(st.find(2)));

//erase()
//1.删除单个元素
st.erase(st.find(100));    //利用find()找到100,然后用erase删除  O(1)
st.erase(100);    //O(logN)
//2.删除一个区间元素
st.erase(first, last);  //删除[first, last)     O(last-first)

//size()
//用来获得set内元素的个数  O(1)

//clear()
//O(N)

2.4 set常见用途

set主要作用是自动去重并按升序排序

3. String

3.1 string的定义

#include <string>   //和string.h是两个不同的头文件

string str;
string str = "abcd";

3.2 string中内容的访问

//通过下标访问
//一般来说可以像字符数组那样去访问string
for(int i = 0; i < str.length(); i++){
    printf("%c",str[i]);
}

//如果要读入和输出整个字符串,则只能用cin 和 cout
cin >> str;
cout << str;
//用c_str()将string类型转化为字符数组后可以用printf来输出
string str = "abcd";
printf("%s", str.c_str());

//通过迭代器访问
string::iterator it;
for(string::iterator it = str.begin(); it != str.end(); it++){
    printf("%c", *it);
}

3.3 string常用函数

//operator+=
string str1 = "abc", str2 = "xyz", str3;
str3 = str1 + str2;    //赋给str3
str1 += str2;       //拼接到str1

//compare operator
//两个string类型可以直接用==, !=, <, <=, >, >=比较大小,比较规则是字典序

//length()/size()
//返回string的长度

//insert()
string str = "abcxyz", str2 = opq;
str.insert(3, str2);   //往str[3]处插入opq
//insert(it,it2,it3)  串[it2,it3)插在it位置上
str.insert(str.begin() + 3, str2.begin(), str2.end());

//erase()
//1.删除单个元素
str.erase(str.begin() + 4);    //删除4号位
//删除一个区间内所有元素
//str.erase(first, last)   删除[first,last)
str.erase(str.begin() + 2, str.end() - 1);
//str.erase(pos, length)  //从pos位置删除length长度
str.erase(3, 2);

//clear()

//substr()
//substr(pos, len)  返回从pos号位开始,长度为len的子串   O(len)
string str = "Thank you for your smile.";
cout << str.substr(0, 5) << endl;

//string::npos
//这是一个常数, 本身是-1, 也可认为是unsigned_int类型的最大值
//用以作为find函数失配时的返回值
#include <string>

using namespace std;

int main(){
    if(string::npos == -1){
        cout << "-1 is true." <<endl;
    }
    if(string::npos == 4294967295){
        cout << "4294967295 is also true." << endl;
    }
}
//两个数都会输出

//find()
//str.find(str2), 当str2是str的子串时, 返回其在str中第一次出现的位置;
//如果str2不是str的子串,那么返回string::npos.
//str.find(str2, pos)   从str的pos号开始匹配str2    
//时间复杂度 O(nm)  nm分别为str 和 str2 的长度

//replace()
str.replace(pos, len, str2);  //把str从pos位开始,长度为len的子串替换为str2
str.replace(it1, it2, str2);  //把str的迭代器[it1, it2)范围的子串替换为str2
//O(str.length())

4. Map映射

map可以将任何基本类型(包括STL容器)映射到任何基本类型

4.1 map定义

map<typename1, typename2> mp;

//如果是字符串到整型的映射,必须使用string而不能用char数组
map<string, int> mp;

map<set<int>, string> mp;

4.2 map容器内元素的访问

//通过下标访问
#include <stdio.h>
#include <map>

using namespace std;

int main(){
    map<char, int> mp;
    mp['c'] = 20;
    mp['c'] = 30;  //20被覆盖
    printf("%d\n", mp['c']);    //输出30
    return 0;
}

//通过迭代器访问
map<typename1, typename2>::iterator it;
//因为map的每一对映射都有两个typename,这决定了必须能通过一个it来同时访问键和值
//map可以通过it->first来访问键, 通过it->second来访问值
#include <stdio.h>
#include <map>

using namespace std;

int main(){
    map<char, int> mp;
    mp['m'] = 20;
    mp['r'] = 30;
    mp['a'] = 40;
    for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++){
        printf("%c %d\n", it->first, it->second);
    }
    return 0;
}
//map会以键从小到大的顺序自动排序
//map和set内部都是使用红黑树实现的

4.3 map常用函数

//find()
//find(key)返回键为key的映射的迭代器   O(logN)
#include <stdio.h>
#include <map>

using namespace std;

int main(){
    map<char, int> mp;
    mp['a'] = 1;
    mp['b'] = 2;
    ma['3'] = 3;
    map<char, int>::iterator it = mp.find('b');
    printf("%c %d\n", it->first, it->second);
    return 0;
}

//erase()
//1.删除单个元素    
mp.erase(it);     //O(1)
mp.erase('b');    //O(logN)
//2.删除一个区间内所有元素
mp.erase(first, last);   //删除[first, last)

//size()
//用来获取map中映射的对数     O(1)

//clear()     O(N)

4.4 map的常见用途

  1. 需要建立字符(或字符串)与整数之间映射的题目,使用map可以减少代码量
  2. 判断大整数或者其他类型数据是否存在的题目,可以把map当bool数组用

5. Queue队列

5.1 queue的定义

//先进先出的容器
#include <queue>
using namespace std;
queue<typename> name;

5.2 queue容器内元素的访问

//由于队列本身就是一种先进先出的限制性数据结构
//只能通过front()来访问队首元素,或是通过back()来访问队尾元素
#include <stdio.h>
#include <queue>

using namespace std;

int main(){
    queue<int> q;
    for(int i = 1; i <= 5; i++){
        q.push(i);
    }
    printf("%d %d\n", q.front(), q.back());
    return 0;
}

5.3 queue常用函数

//push() 入队

//front()

//back()

//pop()  出队

//empty()   检测queue是否为空  空->true 

//size()

5.4 queue常见用途

  1. 广度优先搜索
  2. 使用 pop() 和 front() 函数前,必须用empty() 判断队列是否为空

6. Priority_queue优先队列

6.1 priority_queue的定义

//priority_queue底层是用堆来实现的
//在优先队列中,队首元素一定是当前队列中优先级最高的那个
//可以在任何时候往优先队列中加入元素,其底层数据结构堆会随时调整结构,使得每次队首元素都是优先级最大的
#include <queue>

using namespace std;

priority_queue<typename> name;

6.2 priority_queue容器内元素的访问

//只能通过top()函数来访问队首元素(也可称为堆顶元素)
printf("%d\n", q.top());

6.3 priority_queue常用函数

//push()   O(logN)

//top()    O(1)

//pop()    O(logN)

//empty()  O(1)

//size()   O(1)

6.4 priority_queue内元素优先级的设置

//基本数据类型的优先级设置
//int char double 等

priority_queue<int> q;
priority_queue<int, vector<int>, less<int> > q;
//其中vector<int>填写的是来承载底层数据结构堆的容器
//less<int>是对第一个参数的比较类
//less表示数字大优先级越大,greater表示数字小的优先级越大

//结构体的优先级设置
struct fruit{
    string name;
    int price;
    //对 < 进行重载
    friend bool operator < (fruit f1, fruit f2){
        return f1.price < f2.price;
    }
    //重载后内部以价格高的水果为优先级高
}
priority_queue<fruit> q;

//or
struct cmp{
    bool operator () (fruit f1, fruit f2){
        return f1.price > f2.price
    }
}
priority_queue<fruit, vector<fruit>, cmp> q;

//如果结构体内数据较为庞大,建议使用引用来提高效率
friend bool operator < (const fruit &f1, const fruit &f2){
    return f1.price > f2.price;
}
bool operator () (const fruit &f1, const fruit &f2){
    return f1.price > f2.price;
}

6.5 priority_queue常见用途

  1. 解决贪心问题
  2. 对Dijkstra算法进行优化
  3. 使用 top() 前,必须用empty()判断优先队列是否为空

7. Stack堆

7.1 stack的定义

//后进先出
#include <stack>

using namespace std;

stack<typename> name;

7.2 stack容器内元素的访问

//只能通过top()来访问栈顶元素

7.3 stack常用函数

//push()

//pop()

//top()

//empty()

//size()

//以上复杂度均为O(1)

7.4 stack常见用途

  1. 模拟递归

8. Pair

8.1 pair的定义

//将两个元素绑在一起合成一个元素
#include <utility>

using namespace std;

pair<typename1, typename2> name;
//等同于以下结构体
struct pair{
    typename1 first;
    typename2 second;
};

pair<string, int> p;
pair<string, int> p("haha", 5);  //定义
pair<string, int>("haha", 5);
make_pair("haha", 5);

8.2 pair中元素的访问

//pair中只有两个元素:first和second
//只需按正常结构体的方式去访问即可
pair<string, int> p;
p.first = "haha";       //另一种赋值方式
p.second = 5;
cout << p.first << " " << p.second << endl;

8.3 pair常用函数

//比较操作数
//可以直接使用==, !=, <, <=, >, >= 比较大小
//先以first的大小作为标准,只有当first相等时才去判别second的大小

8.4 pair常见用途

  1. 代替二元结构体
  2. 作为map的键值对来进行插入
#include <iostream>
#include <string>
#include <map>

using namespace std;

int main(){
    map<string, int> mp;
    mp.insert(make_pair("heihei", 5));
    mp.insert(pair<string, int>("ahh", 10));
    for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++){
        cout << it->first << " " << it->second << endl;
    }
    return 0;
}

9. algorithm头文件下常用函数

9.1 max(), min(), abs()

最大值,最小值,绝对值

9.2 swap()

交换 x 和 y 的值

9.3 reverse()

#include <stdio.h>
#include <algorithm>

using namespace std;

int main(){
    int a[10] = {10, 11, 12, 13, 14, 15};
    reverse(a, a + 4);
    for(int i = 0; i < 6; i++){
        printf("%d ", a[i]);
    }
    return 0;
}
//result:13 12 11 10 14 15
//也可对字符串某一段进行反转

9.4 next_permutation()

//给出一个序列在全排列中的下一个序列

//n == 3时全排列为
123
132
213
231
312
321
    
#include <stdio.h>
#include <algorithm>
    
using namespace std;

int main(){
    int a[10] = {1, 2, 3};
    do{
        printf("%d%d%d\n", a[0], a[1], a[2]);
    }while(next_permutation(a, a + 3));
    return 0;
}
//输出上述全排列
//next_permutation在已经到达全排列的最后一个时会返回false

9.5 fill()

//可以把数组或容器中某一区间赋值为某一相同的值
//和memset不同,这里的赋值可以是数组类型对应范围中的任意值
#include <stdio.h>
#include <algorithm>

using namespace std;

int main(){
    int a[5] = {1, 2, 3, 4, 5};
    fill(a, a + 5, 111);
    for(int i = 0; i < 5; i++){
        printf("%d ", a[i]);
    }
    return 0;
}

//result:111 111 111 111 111

9.6 sort()

//排序

int a[6] = {9, 4, 5, 2, -6, -1};
sort(a, a + 4);

//char型数组默认按字典序进行排序

//实现比较函数cmp
//若比较函数不填,则默认按从小到大排序
bool cmp(int a, int b){
    return a > b;
}
sort(a, a + 4, cmp);   //从大到小

//结构体数组排序
struct node{
    int x, y;
}ssd[10];

bool cmp(node a, node b){
    return a.x > b.x;     //按x排序
}

bool cmp(node a, node b){
    if(a.x != b.x)
        return a.x > b.x;
    else
        return a.y < b.y;
}

//容器的排序
//只有vector, string, deque是可以使用sort的

9.7 lower_bound(), upper_bound()

lower_bound(first, last, val) 用来寻找在数组或容器的[first, last)范围内第一个值大于等于val的元素的位置,如果时数组,则返回该位置的指针; 如果是容器,则返回该位置的迭代器。

upper_bound(first, last, val) 用来寻找在数组或容器的[first, last)范围内第一个值大于val的元素的位置,如果时数组,则返回该位置的指针; 如果是容器,则返回该位置的迭代器。

如果数组或容器中没有需要寻找的元素,则二者均返回可以插入该元素位置的指针或迭代器(即假设存在该元素时,元素应当在的位置)。

复杂度均为O(log(last - first))

相关标签: 算法