C++数据结构1

向量

相关知识

数组存在一个限制:创建数组时必须规定大小,因此可能出现开的太大导致内存浪费的现象,或太小导致数组访问越界

因此引入向量:可以改变大小的线性序列容器,与数组相同的是可以通过下标来访问。头文件如下

#include <vector>

vector的状态

  • empty():返回向量是否为空
  • size():返回向量元素个数

vector尾部元素的添加或删除

  • push_back:尾部添加一个元素,string也有
  • pop_back:尾部删除一个元素,string也有

vector元素操作:见词如面

  • insert
  • erase
  • clear

vector迭代器操作

  • begin():返回向量中的首元素的迭代器begin
  • end():返回向量中尾元素后一个位置的迭代器

下面为使用迭代器获取向量的循环方法

vector<int>::iterator it;    // 定义迭代器
for (it = myVector.begin(); it != myVector.end(); it++) {
    printf("%d ", *it);
}

题目

完数VS盈数

完数VS盈数_牛客题霸_牛客网 (nowcoder.com)

描述

一个数如果恰好等于它的各因子(该数本身除外)子和,如:6=3+2+1。则称其为“完数”;若因子之和大于该数,则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。

输入描述

题目没有任何输入。

输出描述

输出2到60之间所有“完数”和“盈数”,并以如下形式输出: E: e1 e2 e3 ......(ei为完数) G: g1 g2 g3 ......(gi为盈数) 其中两个数之间要有空格,行尾不加空格。

#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> yingshu;
    int num;
    printf("E:");
    for (int i = 2; i < 61; i++) {
        num = 0;
        for (int j = 1; j <= i / 2; j++) {
            if (i % j == 0) {
                num += j;
            }
            if (num > i) {
                yingshu.push_back(i);
                break;
            }
        }
        if (num == i) {
            printf(" %d", i);
        }
    }
    printf("\nG:");
    for (int i = 0; i < yingshu.size(); i++) {
        printf(" %d", yingshu[i]);
    }
}

vector在图论中邻接表还有应用

队列

知识

队列(Queue)是一种线性的序列结构,其存放的元素按照现行的逻辑次序排列,但操作仅限于序列的两端【先进先出】

STL-queue 引用头文件如下

#include <queque>

定义方法

queue<typename> name

queue状态:同vector

queue元素添加或删除:push()、pop()

queue元素的访问:front()、back()

题目

约瑟夫问题,猫狗收留领养

队列经常用于宽度优先的搜索

知识

和队列一样,栈也是一种线性序列结构,但操作仅限于特定的一端,和queue的区别在于只能用top()来访问栈顶元素

题目

Zero-complexity Transposition

Zero-complexity Transposition_牛客题霸_牛客网 (nowcoder.com)

描述

You are given a sequence of integer numbers. Zero-complexity transposition of the sequence is the reverse of this sequence. Your task is to write a program that prints zero-complexity transposition of the given sequence.

输入描述

For each case, the first line of the input file contains one integer n-length of the sequence (0 < n ≤ 10 000). The second line contains n integers numbers-a1, a2, …, an (-1 000 000 000 000 000 ≤ ai ≤ 1 000 000 000 000 000).

输出描述

For each case, on the first line of the output file print the sequence in the reverse order.

题目大意就是逆向一组数,需要注意使用long long接收数据,防止溢出

#include <iostream>
#include <stack>
using namespace std;

int main() {
    int n;
    while (scanf("%d", &n)!=EOF) {
        stack<long long> a;
        long long b;
        for (int i = 0; i < n; i++) {
            scanf("%lld", &b);
            a.push(b);
        }
        while (!a.empty()) {
            printf("%lld ", a.top());
            a.pop();
        }
        printf("\n");
    }
    return 0;
}

括号匹配

题目大意是不匹配的左括号输出问号,不匹配的右括号输出美元号

思路:定义一个栈装左括号下标,每匹配一对弹出一个左括号下标,栈空时右括号无法匹配输出美元号,遍历字符串完后栈里还有没匹配的左括号输出问号,剩下的输出空格【预先定义一个和字符串长度的空格字符串】

#include <iostream>
#include <stack>
using namespace std;

int main()
{
    string str;
    while (cin >> str)
    {
        cout << str << endl;
        stack<int> bracket;
        string r(str.size(), ' ');
        for (int i = 0; i < str.size(); i++)
        {
            if (str[i] == ')' && bracket.empty())
                r[i] = '?';
            else if (str[i] == '(') 
                bracket.push(i);
            else if (str[i] == ')' && !bracket.empty())
                bracket.pop();
        }
        while(!bracket.empty())
        {
            r[bracket.top()] = '$';
            bracket.pop();
        }
        cout << r << endl;
    }
    return 0;
}

堆栈使用

堆栈的使用_牛客题霸_牛客网 (nowcoder.com)

描述

堆栈是一种基本的数据结构。堆栈具有两种基本操作方式,push 和 pop。其中 push一个值会将其压入栈顶,而 pop 则会将栈顶的值弹出。现在我们就来验证一下堆栈的使用。(注:本题有多组输入,可以参考该网址:https://www.nowcoder.com/discuss/276

输入描述

对于每组测试数据,第一行是一个正整数 n(0 < n <= 10000)。而后的 n 行,每行的第一个字符可能是'P'或者'O'或者'A';如果是'P',后面还会跟着一个整数,表示把这个数据压入堆栈;如果是'O',表示将栈顶的值 pop 出来,如果堆栈中没有元素时,忽略本次操作;如果是'A',表示询问当前栈顶的值,如果当时栈为空,则输出'E'。堆栈开始为空。

输出描述

对于每组测试数据,根据其中的命令字符来处理堆栈;并对所有的'A'操作,输出当时栈顶的值,每个占据一行,如果当时栈为空,则输出'E'。

需要注意:可以边输入边输出的

#include <iostream>
#include <stack>
using namespace std;

int main() {
    int n, num;
    string c;
    while (scanf("%d", &n)!=EOF) {
        stack<int> s;
        for (int i  = 0; i < n; i++) {
            cin >> c;
            if (c == "P") {
                scanf("%d", &num);
                s.push(num);
            } else if (c == "O" && !s.empty()) {
                s.pop();
            } else if (c == "A") {
                if (s.empty())
                    printf("E\n");
                else
                    printf("%d\n", s.top());
            }
        }
    }
}

简单计算器

描述

读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。

输入描述

测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,整数和运算符之间用一个空格分隔。没有非法表达式。当一行中只有0时输入结束,相应的结果不要输出。

输出描述

对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。

输入:
1 + 2
4 + 2 * 5 - 7 / 11
0
输出:
3.00
13.36

思路:设计两个栈,分别装数字和计算符号;同时is_prior用来判断符号优先级

#include <iostream>
#include <stack>
#include <math.h>
#include <string>
using namespace std;

float calc(float num1, float num2, char op) {
    if (op == '+')
        return num1 + num2;
    else if (op == '-')
        return num1- num2;
    else if (op == '*')
        return num1 * num2;
    else
        return num1 / num2 * 1.0;
}

int op2num(char op) {
    if (op == '+')
        return 0;
    else if (op == '-')
        return 1;
    else if (op == '*')
        return 2;
    else
        return 3;
}

bool is_prior(char op1, char op2) {    //思路是同级或小的,可以计算;优先级大的等下一个在计算
    bool cp[4][4] = {{false, false, true, true}, {false, false, true, true}, {false, false, false, false}, {false, false, false, false}};
    return cp[op2num(op1)][op2num(op2)];
}

int main() {
    string exp;
    while (getline(cin, exp)) {
        stack<float> num;
        stack<char> ops;
        exp = exp + " ";
        int n = 0;
        if (exp == "0 ")
            break;
        else {
            for (int i = 0; i < exp.size(); i++) {
                if (exp[i] == ' ' && (exp[i-1] <= '9' && exp[i-1] >= '0')) {
                    num.push(n);    // 只有当前字符为空格且上一个为数字才push数字
                    n = 0;
                } else if (exp[i] <= '9' && exp[i] >= '0') {
                    n = n * 10 + (exp[i] - '0');    // 字符转数字
                } else if (exp[i] == '+' || exp[i] == '-' || exp[i]== '*' || exp[i] == '/') {
                    while (!ops.empty() && !is_prior(ops.top(), exp[i])) {    //直到同优先级的计算完再填入当前计算符
                        float num1 = num.top();
                        num.pop();
                        float num2 = num.top();
                        num.pop();
                        num.push(calc(num2, num1, ops.top()));
                        ops.pop();
                    }
                    ops.push(exp[i]);
                }
            }
            while (!ops.empty()) {    // 计算字符全部装完,遍历即可
                float num1 = num.top();
                num.pop();
                float num2 = num.top();
                num.pop();
                num.push(calc(num2, num1, ops.top()));
                ops.pop();
            }
        }
        printf("%.2f\n", num.top());    // 保留两位小数
    }
    return 0;
}

计算表达式

计算表达式_牛客题霸_牛客网 (nowcoder.com)

描述

对于一个不存在括号的表达式进行计算

输入描述

存在多组数据,每组数据一行,表达式不存在空格

输出描述

输出结果

输入:
6/2+3+3*4
输出:
18

思路:本题和上一题几乎一样,唯一需要注意的本题不严谨,输出格式有的是int有的是float,所以最好使用c++标准输出cout来输出,这样不用printf里规定%d还是%f了;同时本题没有空格,因此最后结束遍历表达式需要再push一次数字

#include <iostream>
#include <stack>
#include <math.h>
#include <string>
using namespace std;

float calc(float num1, float num2, char op) {
    if (op == '+')
        return num1 + num2;
    else if (op == '-')
        return num1- num2;
    else if (op == '*')
        return num1 * num2;
    else
        return num1 / num2;
}

int op2num(char op) {
    if (op == '+')
        return 0;
    else if (op == '-')
        return 1;
    else if (op == '*')
        return 2;
    else
        return 3;
}

bool is_prior(char op1, char op2) {    //思路是同级或小的,可以计算;优先级大的等下一个在计算
    bool cp[4][4] = {{false, false, true, true}, {false, false, true, true}, {false, false, false, false}, {false, false, false, false}};
    return cp[op2num(op1)][op2num(op2)];
}

int main() {
    string exp;
    while (getline(cin, exp)) {
        stack<float> num;
        stack<char> ops;
        int n = 0;
        for (int i = 0; i < exp.size(); i++) {
            if (exp[i] <= '9' && exp[i] >= '0') {
                n = n * 10 + (exp[i] - '0');    // 字符转数字
            } else {
                num.push(n);    // 只有当前字符为空格且上一个为数字才push数字
                n = 0;
                while (!ops.empty() && !is_prior(ops.top(), exp[i])) {
                    float num1 = num.top();
                    num.pop();
                    float num2 = num.top();
                    num.pop();
                    num.push(calc(num2, num1, ops.top()));
                    ops.pop();
                }
                ops.push(exp[i]);
            }
        }
        num.push(n);
        while (!ops.empty()) {    // 计算字符全部装完,遍历即可
            float num1 = num.top();
            num.pop();
            float num2 = num.top();
            num.pop();
            num.push(calc(num2, num1, ops.top()));
            ops.pop();
        }
        cout << num.top() << endl;    // 保留两位小数
    }
    return 0;
}
最后修改:2023 年 06 月 23 日
如果觉得我的文章对你有用,请随意赞赏