ACM训练笔记之数据结构的应用


前言

本文主要是记录ACM训练的笔记,本周主要学习了数据结构中线性结构的应用


一、数据结构之栈是什么?

栈是一种只能从表的一端存取数据且遵循 “先进后出” 原则的线性存储结构。

基于栈结构的特点,在实际应用中,通常只会对栈执行以下两种操作:

向栈中添加元素,此过程被称为"进栈"(入栈或压栈);

从栈中提取出指定元素,此过程被称为"出栈"(或弹栈)

二、STL库的使用

1.stack

stack s;

stack< int, vector > stk; //覆盖基础容器类型,使用vector实现stk

s.empty(); //判断stack是否为空,为空返回true,否则返回false

s.size(); //返回stack中元素的个数

s.pop(); //删除栈顶元素,但不返回其值

s.top(); //返回栈顶元素的值,但不删除此元素

s.push(item); //在栈顶压入新元素item

经典应用:括号匹配

我们可以用 stack 容器来实现一个简单的计算器程序。这个程序支持一些基本的加、 减、乘、除、幂操作。它们分别对应运算符 +、-、*、/、^。幂操作由定义在头文件 cmath 中的 pow() 函数提供。表达式以单行字符串的形式读入,可以包含空格。在解析字符串之前可以使用 remove() 算法来移除输入表达式中的空格,然后再执行这个表达式所包含的运算。

代码如下(示例):

// A simple calculator using stack containers
#include <cmath>                                          // For pow() function
#include <iostream>                                       // For standard streams
#include <stack>                                          // For stack<T> container
#include <algorithm>                                      // For remove()
#include <stdexcept>                                      // For runtime_error exception
#include <string>                                         // For string class
using std::string;

// Returns value for operator precedence
inline size_t precedence(const char op)
{
    if (op == '+' || op == '-')
        return 1;
    if (op == '*' || op == '/')
        return 2;
    if (op == '^')
        return 3;
    throw std::runtime_error {string {"invalid operator in precedence() function: "} + op};
}

// Execute an operation
double execute(std::stack<char>& ops, std::stack<double>& operands)
{
    double result {};
    double rhs {operands.top()};                            // Get rhs...
    operands.pop();                                         // ...and delete from stack
    double lhs {operands.top()};                            // Get lhs...
    operands.pop();                                         // ...and delete from stack

    switch (ops.top())                                      // Execute current op
    {
        case '+':
            result = lhs + rhs;
            break;
        case '-':
            result = lhs - rhs;
            break;
        case '*':
            result = lhs * rhs;
            break;
        case '/':
            result = lhs / rhs;
            break;
        case '^':
            result = std::pow(lhs, rhs);
            break;
        default:
            throw std::runtime_error {string{"invalid operator: "} + ops.top()};
    }
    ops.pop();                                              // Delete op just executed
    operands.push(result);
    return result;
}

int main()
{
    std::stack<double> operands;                            // Push-down stack of operands
    std::stack<char> operators;                             // Push-down stack of operators
    string exp;                                             // Expression to be evaluated
    std::cout << "An arithmetic expression can include the operators +, -, *, /, and ^ for exponentiation." << std::endl;
    try
    {
        while (true)
        {
            std::cout << "Enter an arithmetic expression and press Enter - enter an empty line to end:" << std::endl;
            std::getline(std::cin, exp, '\n');
            if (exp.empty()) break;

            // Remove spaces
            exp.erase(std::remove(std::begin(exp), std::end(exp), ' '), std::end(exp));

            size_t index {};                                    // Index to expression string

            // Every expression must start with a numerical operand
            operands.push(std::stod(exp, &index));              // Push the first (lhs) operand on the stack

            while (true)
            {
                operators.push(exp[index++]);                     // Push the operator on to the stack

                // Get rhs operand
                size_t i {};                                      // Index to substring
                operands.push(std::stod(exp.substr(index), &i));  // Push rhs operand
                index += i;                                       // Increment expression index

                if (index == exp.length())                        // If we are at end of exp...
                {
                    while (!operators.empty())                      // ...execute outstanding ops
                        execute(operators, operands);
                    break;
                }

                // If we reach here, there's another op...
                // If there's a previous op of equal or higher precedence execute it
                while (!operators.empty() && precedence(exp[index]) <= precedence(operators.top()))
                    execute(operators, operands);                   //  Execute previous op.
            }
            std::cout << "result = " << operands.top() << std::endl;
        }
    }
    catch (const std::exception& e)
    {
        std::cerr << e.what() << std::endl;
    }
    std::cout << "Calculator ending..." << std::endl;
}

这个程序通过从左到右扫描的方式来分析输入表达式,并且会将运算符保存到 stack 容器 operators 中。操作数存放在 stack 容器 operands 中。所有的运算符都需要两个操作数,所以每执行一次运算,都需要获取一个 operators 栈顶的运算符,以及两个 operands 栈顶的操作数

2.举个例子

题目如下:
As the new term comes, the Ignatius Train Station is very busy nowadays. A lot of student want to get back to school by train(because the trains in the Ignatius Train Station is the fastest all over the world v). But here comes a problem, there is only one railway where all the trains stop. So all the trains come in from one side and get out from the other side. For this problem, if train A gets into the railway first, and then train B gets into the railway before train A leaves, train A can’t leave until train B leaves. The pictures below figure out the problem. Now the problem for you is, there are at most 9 trains in the station, all the trains has an ID(numbered from 1 to n), the trains get into the railway in an order O1, your task is to determine whether the trains can get out in an order O2.

input:
The input contains several test cases. Each test case consists of an integer, the number of trains, and two strings, the order of the trains come in:O1, and the order of the trains leave:O2. The input is terminated by the end of file. More details in the Sample Input.

output:
The output contains a string “No.” if you can’t exchange O2 to O1, or you should output a line contains “Yes.”, and then output your way in exchanging the order(you should output “in” for a train getting into the railway, and “out” for a train getting out of the railway). Print a line contains “FINISH” after each test case. More details in the Sample Output.

样例输入:
3 123 321
3 123 312

样例输出:
Yes.
in
in
in
out
out
out
FINISH
No.
FINISH

题意:
题意:给出火车在进站口的顺序,火车进站,出站遵循先进后出的规律,问能实现出站顺序如给出的顺序吗?能输出步骤,不能输出No

分析:
分析:用栈来模拟过程并记录出入栈操作即可,通过栈是否空判断YES NO

代码如下:

#include<iostream>
#include<cstdio>
#include<stack>
using namespace std;
const int maxn = 10;
int main()
{
    int N;
    while (~scanf("%d",&N))
    {
        bool flag = true;
        stack<int>s;
        int i,a[maxn] = {0},b[maxn],c[maxn];
        char s1[maxn],s2[maxn];
        scanf("%s %s",s1,s2);
        for (i = 0; i < N; i++)
            b[i] = s1[i] - '0';
        for (i = 0; i < N; i++)
            c[i] = s2[i] - '0';
 
        int j = 0,k = 0;
        i = 0;
        for (i = 0; i < N; i++)
        {
            if (b[i] != c[j])
            {
                a[k++] = 0;
                s.push(b[i]);
            }
            else if (b[i] == c[j])
            {
                a[k++] = 0;
                j++;
                a[k++] = 1;
                while (!s.empty() && s.top() == c[j])
                {
                    j++;
                    a[k++] = 1;
                    s.pop();
                }
            }
        }
        while (!s.empty())
        {
            if (s.top() != c[j])
            {
                flag = false;
                break;
            }
            else
            {
                j++;
                s.pop();
                a[k++] = 1;
            }
        }
        if (!flag)
            printf("No.\nFINISH\n");
        else
        {
            printf("Yes.\n");
            for (i = 0; i < k; i++)
                a[i]?printf("out\n"):printf("in\n");
            printf("FINISH\n");
        }
    }
    return 0;
}

总结

由于时间很仓促,一些内容还未完善好,这周会继续做完。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值