ACM第一周总结(STL)

目录:

一,STL

基础内容:

进阶知识:

1.vector

应用场景:

2.stack

应用场景:

栈的例题:

3.queue

应用场景:

4.priority_queue 优先队列

概念解析:

例题:

6.sort

应用场景:

例题:(关于结构体排序的一道题目)

7.unique(去重函数)

应用场景:

8.next_permutation(全排列)

分析:

9.upper_bound、lower_bound

解析:

10.set/multiset(集合)

11.map/multimap

分析:

应用例题:

题目分析:

二,图的最短路径算法

三,最终总结:


本周学习内容:

1.STL的应用。

2.搜索方面的一些知识。

3.图论最短路径生成。

一,STL

基础内容:

STL数据库复习_钟一淼的博客-CSDN博客

STL函数补充_钟一淼的博客-CSDN博客

淼淼的STL总结_钟一淼的博客-CSDN博客

进阶知识:

1.vector

应用场景:

a.适用于随机访问,访问量比较大(因为随机访问的时间复杂度只有O(1)),相对而言插入和删除操作较小。

b.结合本周所学习的图论,可以用vector建立邻接表,代码如下:

struct node {
    int s1;//记录结点
    int side;//边权
}
vector<node>mp[maxn];//本身就可以存储结构体
//也可以用vector<pair<int,int>>s
init();//初始化mp
node h;
//循环输入
int x,y,r;   
h.s1 = y;
h.side = r;
mp[x].push_back(h);//从x到y,路径为r

注意的是vector可以设为二维数组进行操作。 (pair的用法之前有讲)。

c.经典->约瑟夫问题

P1996 约瑟夫问题

题目描述

n 个人围成一圈,从第一个人开始报数,数到 m 的人出列,再由下一个人重新从 1 开始报数,数到 m 的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

注意:本题和《深入浅出-基础篇》上例题的表述稍有不同。书上表述是给出淘汰 n-1 名小朋友,而该题是全部出圈。

输入格式:

输入两个整数 n,m。

输出格式:

输出一行 n个整数,按顺序输出每个出圈人的编号。

输入输出样例:

输入:

10 3

输出:

3 6 9 2 7 1 8 5 10 4

说明/提示:

1≤m,n≤100

 题目分析:

1.本题形成了一个圆桌问题。(寻找到的点对数组现有元素个数进行取余)

2.找到的点删除,直到数组为空。

#include <iostream>
#include <vector>
using namespace std;
vector<int>s;
//感觉知识掌握的还是不够牢固
int main()
{
    int n, m;
    int pos = 0;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        s.push_back(i);
    }
    while (!s.empty()) {
        pos = (pos + m-1) % s.size();
        cout << s[pos] << " ";
        s.erase(s.begin()+pos);
    }
}

2.stack

应用场景:

1.需要逆序输出时。(因为栈的最大特点就是先进后出

2.计算后缀表达式。(例如:括号匹配,符号成对出现等)

3.数制转换也可以用栈来实现。

栈的例题:

例题1:(解释一下,我本来想直接粘贴题目的,奈何推荐受限)

P1449 后缀表达式

题目描述:

所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。

如:3*(5–2)+7对应的后缀表达式为:3.5.2.-*7.+@。’@’为表达式的结束符号。‘.’为操作数的结束符号。

输入格式:

输入:后缀表达式

输出格式:

输出:表达式的值

输入输出样例:

输入:

3.5.2.-*7.+@

输出 :

16

说明/提示:

字符串长度,1000内。

题目分析:

1.首先必须了解后缀表达式是如何计算的(一看就会的知识

2.字符串转化数字,当遍历到“.”时,压入栈内。

3.遇到数乘符号时弹出两个栈顶元素,计算之后再次压入栈内,循环,直到遇到“@”结束循环,栈内剩余值,即为后缀表达式所求值。

代码如下:

#include <iostream>
#include <stack>
#include <cstdio>
using namespace std;
int s=0;
char ch;
stack<int>n;
int main()
{
    int x;
    int y;
    
    do {
        ch = getchar();
        if (ch >= '0' && ch <= '9') {
            s = s * 10 + ch - '0';
        }
        else if (ch == '.') {
            n.push(s);
            s = 0;
        }
        else if (ch != '@') {
            x = n.top(); n.pop();
            y= n.top(); n.pop();
            switch (ch)
            {
            case '+':n.push(x + y); break;
            case '-':n.push(y-x); break;//是栈顶的第二个元素-第一个元素
            case '*':n.push(x *y); break;
            case '/':n.push(y/x); break;
            }
        }
    } while (ch != '@');
    cout << n.top()<<endl;//取剩余的栈顶元素
  
}

例题2:

十进制转二进制,(因为栈这个本质是一个先进后出的结构)。

#include <iostream>
#include <vector>
#include <stack>
using namespace std;
vector<int>s;
//感觉知识掌握的还是不够牢固
int main()
{
    stack<int>s;
    int n;
    cin >> n;
    while (n>0) {
        s.push(n % 2);
        n = n / 2;
    }
    int size = s.size();
    for (int i =0; i <size; i++) {
        cout << s.top();
        s.pop();
    }
}

3.queue

应用场景:

1.队列这个应用场景相对而言会更加广泛一点,首先它是一个先进先出的结构类型。

2.结合这个星期所学的,主要应用在BFS(广度优先搜索)。

3.图的最短路径(SFPA算法中有应用)

详情队列使用请看:

SPFA算法(最短路径算法)_钟一淼的博客-CSDN博客

BFS迷宫问题_钟一淼的博客-CSDN博客

        总体来说,这是我最熟悉的STL里的函数,队列的使用范围是比较广泛的,但是仍然要注意队列的一些基础操作。特别是关于搜索问题的回溯方面,一定要特别注意。

4.priority_queue 优先队列

概念解析:

无非就是优先级高的先进行出队操作。就是个大顶堆的操作,最大的元素在堆顶(回想堆排序我到现在还没写,今晚赶出来

例题:

(这里例题来源于费费的课件,因为我觉得这个题目就很适合我理解优先队列的使用,我很菜

判断下列的点哪个离原点最远,并输出那个点的x,y值。

输入:(输入n,接下来输入n个点)

3
3 2
1 2
2 2

输出:(输出最大距离那个点的x,y坐标)

3 2

利用优先队列,运算符重载,代码如下:

#include<iostream>
#include <queue>
#define pow2(a)((a)*(a))//宏定义
#define dist2(x,y)(pow2(x)+pow2(y))
using namespace std;
struct node {
    int x;
    int y;
    friend bool operator<(node a,node b) {//运算符重载,重载这个"<"
        return (dist2(a.x, a.y) < dist2(b.x, b.y));
        /*const bool operator<(const node&b){//运算符重载,重载这个"<"
    return (dist2(x,y)<dist2(b.x,b.y));
    }(这个报错了)*/
    }
};
int main()
{
    priority_queue<node>s;
    int n;
    int x, y;
    cin >> n;
    while (n--) {
        node p;// p定义一个结构体类型的变量,接收x,y;
        cin >> x >> y;
        p.x = x; p.y = y;
        s.push(p);
    }
    cout << s.top().x << " " << s.top().y << endl;
}

6.sort

 sort,可谓是我接触的最多的函数了。

应用场景:

1.给无序数组进行排序。(可以是任何类型,进行降序,升序)

2.用于结构体排序(应用十分广泛,主要是将bool cmp函数给写好,自定义排序准则)

例题:(关于结构体排序的一道题目)

P1068 [NOIP2009 普及组] 分数线划定 

输入 :

6 3 
1000 90 
3239 88 
2390 95 
7231 84 
1005 95 
1001 88

输出:

88 5 
1005 95 
2390 95 
1000 90 
1001 88 
3239 88 

  题目分析:(说实话,我都不想分析,对我来说这个不太难懂

1.思考问题:bool 函数该如何写?先按成绩从降序排列,如果成绩相同按学号升序排列。

2.思考问题2:如何去统计和m*1.5分数相同的人,用循环找到最后一个和这个分数相同的人的下标。从上到下输出即可。

代码如下:

#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
struct student {
    int nums;
    int score;
}a[6000];
bool cmp(student x, student y) {//判断准则
    if (x.score == y.score) {
        return x.nums < y.nums;
    }
    return x.score > y.score;
}
int main()
{
    int n, m;
    int p = 0;
    int k = 0;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i].nums >> a[i].score;
    }
    sort(a + 1, a + n + 1, cmp);
    p =floor(m*1.5);
    for (int i = p; i <= n; i++) {
        if (a[p].score == a[i].score) {
            k = i;//记录下标
        }
    }
    cout << a[p].score << " " << k << endl;
    for (int i = 1; i <= k-1; i++) {
        cout << a[i].nums << " " << a[i].score << endl;
    }
    cout << a[k].nums << " " << a[k].score;
}

7.unique(去重函数)

应用场景:

就是去除相邻元素的重复值,只保留一个相同的元素。

所以,注意的是使用之前先用sort进行排序。(其实重复的值并没有被删除,而是排到了数组后面去了)。

代码实现一下(特别水):

#include<iostream>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    int a[100];
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    sort(a, a + n);
    int h = unique(a, a + n) - a;//用一个新的数接收去重之后数组的长度
    for (int i = 0; i < h; i++) {
        cout << a[i] << " ";
    }
}

8.next_permutation(全排列)

分析:

字典序进行全排列。

我们学校的例题:

 水一道代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
int main()
{
    int n;
    cin >> n;
    int a[15];
    for (int i = 1; i <= n; i++) {
        a[i] = i;
    }
    do {

        for (int i = 1; i <= n; i++) {
            cout << a[i] << " ";
        }
        cout << endl;

    } while (next_permutation(a + 1, a + n + 1));

}

9.upper_bound、lower_bound

解析:

upper_bound:返回>所给数值元素的第一个位置。

lower_bound:返回>=所给数值元素的第一个位置。

10.set/multiset(集合)

        基础知识里面基本操作总结的已经很全面了,因为本人只做过一道关于set集合的题目,具体应用场景还待我继续研究(其实我是真的不知道这个用在哪

11.map/multimap

分析:

映射的原理,用键值返回元素。

应用例题:

P5266 【深基17.例6】学籍管理

题目描述:

输入输出样例

输入 :

5
1 lxl 10
2 lxl
3 lxl
2 lxl
4

输出:

OK
10
Deleted successfully
Not found
0

题目分析:

1.深入浅出上的例题,个人觉得比较经典,4个操作,储存(用姓名作为键值,储存映射成绩)。

2. 查询和删除,注意find函数,如果查询不到就返回最后一个迭代器的位置,可以用于检查这个人是都存在。

3.剩下的就是计算当前map元素个数,size即可,分支结构而已,算是比较基础的了。

#include <iostream>
#include <map>
using namespace std;
map<string, int>s;
int n,m;
string name;
int score;
int main()
{
    cin >> n;
    while (n--) {
        cin >> m;
        if (m == 1) {
            cin >> name >> score;
            s[name] = score;
            cout << "OK" << endl;
        }
        else if (m == 2) {
            cin >> name;
            if (s.find(name) != s.end()) {
                cout << s[name] << endl;
            }
            else {
                cout << "Not found" << endl;
            }
        }
        else if (m == 3) {
            cin >> name;
            if (s.find(name) != s.end()) {
                s.erase(s.find(name));
                cout << "Deleted successfully" << endl;
            }
            else {
                cout << "Not found" << endl;
            }
        }
        else {
            cout << s.size() << endl;
        }
    }
  
}

二,图的最短路径算法

直接看我关于图的总结吧->

图论:图的四种最短路径算法_钟一淼的博客-CSDN博客

三,最终总结:

1.个人觉得还是在细节上的把握很差。(特别是STL在算法中应用很广泛)

2.周六周日的任务就是将这周所学习的知识复习,不能只贪图速度而忽视效率。

3.算法这个东西就是要多思考,不能盲目的刷题,这周的东西还是不少,灵活运用才是关键。

4.也是刚开始写这个博客,所以有什么不好的地方还是需要及时指正。

5.希望能通过本周的学习,复习,总结,形成更强的知识网络体系,最终实践在题目中去。

        那这周的总结就到这里结束了,细节的补充还会继续更新,生死看淡,不服就干!

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟一淼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值