【华为od刷题(C++)】HJ77 火车进站

我的代码:

#include <iostream>//用于输入输出流
#include <vector>//用于存储动态数组
#include <queue>//用于队列数据结构(FIFO)
#include <stack>//用于栈数据结构(LIFO)
#include <algorithm>//提供排序等算法的功能

using namespace std;//表示使用标准库中的所有组件

vector<string> result;//result 用于存储每次递归调用时生成的栈操作序列

// 写入结果
/*这个函数接受一个队列 q 作为输入,
将队列中的元素依次转换为字符串,
并添加到 result 向量中
最后将完整的栈操作序列(一个字符串)保存下来*/
void write_result(queue<int> q) {
    string str;
    //声明了一个空的字符串 str,用来存储队列元素转换为字符串后的结果

    while (!q.empty()) {
        //使用 while 循环遍历队列中的元素,直到队列为空
        //q.empty() 检查队列是否为空,如果为空,循环停止

        str += to_string(q.front());
        //q.front() 获取队列的第一个元素
        //to_string(q.front()) 将队列中的整数元素转换为字符串
        //str += 将转换后的字符串添加到 str 的末尾

        str += ' ';
        //每个元素转换为字符串后,会在后面加一个空格,方便后续拼接其他元素

        q.pop();
        //q.pop() 移除队列中的第一个元素,以便接着处理下一个元素
        //队列是先进先出(FIFO)的,因此 pop() 会把第一个入队的元素移除
    }
    result.push_back(str);
    //将完成拼接后的字符串 str 添加到全局变量 result 的末尾
    //result 是一个 vector<string>,用来存储所有拼接结果
}

// 递归求解
void solve(queue<int> in, stack<int> t, queue<int> out, bool flag) {
    //in:输入队列,存放待处理的数据
    //t:栈,用于模拟栈的入栈和出栈操作
    //out:输出队列,存放最终的结果
    //flag:标记,决定当前操作是入栈还是出栈

    if (in.empty()) {
        //如果 in 队列为空,表示所有数据已经入栈

        if (flag)             
            return;
            //此时如果 flag 为 true,表示不允许再执行入栈操作,直接返回

        //如果栈 t 还有数据,弹出栈顶元素并将其加入 out 队列,直到栈为空
        while (!t.empty()) {
            out.push(t.top());
            t.pop();
        }

        write_result(out);
        //调用 write_result(out) 来记录结果

        return;
    } else {
        if (flag) {
            //如果 flag 为 true,表示进行入栈操作

            t.push(in.front());
            //将 in 队列的第一个元素 in.front() 入栈

            in.pop();
        } else {
            //如果 flag 为 false,表示进行出栈操作

            //只有栈 t 非空时才能进行出栈,否则直接返回
            if (t.empty())    
                return;
            out.push(t.top());
            t.pop();
        }

        // 递归
        solve(in, t, out, false);
        //第一个递归调用 solve(in, t, out, false) 负责出栈操作

        solve(in, t, out, true);
        //第二个递归调用 solve(in, t, out, true) 负责入栈操作
    }
}

int main() {
    int num;
    while (cin >> num) {
        //输入一个整数 num,表示待处理的数字的数量

        int sequence;
        queue<int> in, out;
        stack<int> t;

        //输入一个包含 num 个整数的序列,将这个序列作为输入队列 in
        for (int i = 0; i < num; ++i) {
            cin >> sequence;
            in.push(sequence);
        }

        solve(in, t, out, true);
        /*调用 solve 函数来模拟栈操作
        in 是输入队列,t 是栈,out 是输出队列,
        true 表示开始时进行入栈操作*/

        sort(result.begin(), result.end());
        //对生成的栈操作序列(存储在 result 向量中)按字典顺序排序

        //通过迭代器遍历 result 向量,并逐个输出每个栈操作序列
        for (auto it = result.begin(); it != result.end(); ++it) {
            cout << *it << endl;
        }
        
        result.clear();
        //result.clear();:清空 result 向量,以便下一次循环使用
    }
    return 0;
}

这段代码的功能是模拟栈操作,并通过递归方法生成栈的操作序列;总结思路如下:

主要功能:

  1. 输入处理:

    程序从标准输入获取一组整数,存储到队列 in 中
  2. 递归求解栈操作:

    • 使用递归的方式,通过入栈和出栈的操作来模拟栈的转换
    • 每个递归过程选择是进行入栈操作(将队列中的元素压入栈)还是进行出栈操作(从栈中弹出元素并加入输出队列)
    • 递归过程中,flag 用来标记是执行入栈还是出栈操作
  3. 记录结果:

    • 当队列 in 为空时,说明所有元素已处理完,程序会将栈中的元素依次弹出并存入 out 队列中,记录栈的操作结果
    • 结果会保存在 result 向量中,格式为字符串形式,记录了每次操作的队列状态
  4. 排序和输出:

    • 对生成的所有栈操作序列进行字典顺序排序
    • 最后将所有排序后的结果输出到标准输出

代码分析:

  • write_result(queue<int> q):将队列中的元素转换为字符串并存入 result 向量;队列的元素被依次读取并转换为字符串,然后连接成一个大的字符串,最后将其保存到 result

  • solve(queue<int> in, stack<int> t, queue<int> out, bool flag):核心递归函数,控制栈的入栈和出栈操作。递归地进行两种操作:

    1. 入栈(当 flag 为 true 时,执行入栈操作)
    2. 出栈(当 flag 为 false 时,执行出栈操作)
  • main():处理输入并调用递归函数 solve;对结果进行排序后输出,并清空 result 以便下一次计算

具体操作:

  1. 入栈操作: 每次将队列中的一个元素压入栈 t 中,递归处理
  2. 出栈操作: 每次从栈中弹出元素并添加到输出队列 out 中,递归处理
  3. 递归终止的条件是当队列为空且栈中的元素已经处理完

总结:

  • 程序通过递归的方式模拟了栈的操作,尝试所有可能的栈操作序列,并记录每次的队列状态
  • 生成的所有栈操作序列按字典顺序排序后输出
  • flag 起到了控制递归过程中入栈和出栈操作的作用,递归地生成所有可能的栈操作序列,并最终输出结果

假设输入的数字序列是:1 2 3,即我们有三个数字需要处理;我们将依次执行入栈和出栈操作,来模拟这些数字通过栈的过程

初始状态:

  • 输入队列 in = [1, 2, 3]
  • 输出队列 out = []
  • 栈 t = []
  • 递归标记 flag = true,表示从队列 in 中入栈

递归过程:

  1. 第一次递归(flag = true

    • 从输入队列 in 中取出元素 1,并入栈
    • 当前状态:
      • in = [2, 3]
      • t = [1]
      • out = []
    • 递归调用 solve(in, t, out, false) 进行出栈操作
  2. 第二次递归(flag = false

    • 栈非空,从栈中弹出 1,并加入输出队列 out
    • 当前状态:
      • in = [2, 3]
      • t = []
      • out = [1]
    • 递归调用 solve(in, t, out, true) 进行入栈操作
  3. 第三次递归(flag = true

    • 从输入队列 in 中取出元素 2,并入栈
    • 当前状态:
      • in = [3]
      • t = [2]
      • out = [1]
    • 递归调用 solve(in, t, out, false) 进行出栈操作
  4. 第四次递归(flag = false

    • 栈非空,从栈中弹出 2,并加入输出队列 out
    • 当前状态:
      • in = [3]
      • t = []
      • out = [1, 2]
    • 递归调用 solve(in, t, out, true) 进行入栈操作
  5. 第五次递归(flag = true

    • 从输入队列 in 中取出元素 3,并入栈
    • 当前状态:
      • in = []
      • t = [3]
      • out = [1, 2]
    • 递归调用 solve(in, t, out, false) 进行出栈操作
  6. 第六次递归(flag = false

    • 栈非空,从栈中弹出 3,并加入输出队列 out
    • 当前状态:
      • in = []
      • t = []
      • out = [1, 2, 3]
    • 递归返回,处理完所有元素

结果记录:

  • 当前的栈操作序列是 1 2 3,我们将其保存到 result 向量中

进一步递归:

递归的过程是一个深度优先搜索,搜索树的每个节点表示一次操作;在一个节点上,可能有两种操作:

  • 入栈操作:如果输入队列不为空,则可以进行入栈操作
  • 出栈操作:如果栈不为空,则可以进行出栈操作

举个例子

假设输入队列是 [1, 2, 3],我们将递归调用分为两个主要分支:入栈出栈

  • 第一层递归in = [1, 2, 3]t = []out = [],我们选择入栈 1,然后进入下一层递归

    • 第二层递归in = [2, 3]t = [1]out = [],我们选择入栈 2,然后进入下一层递归

      • 第三层递归in = [3]t = [1, 2]out = [],我们选择入栈 3,然后进入下一层递归

        • 第四层递归in = []t = [1, 2, 3]out = [],此时输入队列为空,可以开始出栈操作

          • 出栈操作:从栈中依次弹出元素,形成一个有效的栈操作序列 [1, 2, 3]
        • 由于已经处理完所有元素,递归回退到上一层。

      • 在第三层递归中,我们还可以选择出栈,首先出栈 2,再回到上一层进行其他操作

      • 继续递归,直到所有可能的栈操作序列都被遍历

为什么递归会产生不同的栈操作序列?

在递归的过程中,入栈和出栈的顺序决定了栈操作序列的最终结果;例如,某些递归分支中,我们可能先入栈某个元素,而在其他分支中可能先出栈已入栈的元素;这种顺序的不同,会导致不同的栈操作序列

举个例子来说明

假设我们现在输入队列为 [1, 2, 3],递归过程中可能会产生如下几种不同的栈操作序列:

  1. 序列 11 2 3(依次入栈,再依次出栈)
  2. 序列 21 3 2(先出栈 1,再入栈 2,再出栈 2,最后出栈 3)
  3. 序列 32 1 3(先入栈 2,然后再出栈 1,再出栈 3)
  4. 序列 42 3 1(先出栈 2,再出栈 3,最后出栈 1)
  5. 序列 53 1 2(先入栈 3,然后再出栈 1,再出栈 2)
  6. 序列 63 2 1(先入栈 3,接着入栈 2,再出栈 1,最后出栈 2)

排序和输出:

在所有递归操作完成后,所有的栈操作序列将被保存在 result 向量中;我们对这些序列进行字典顺序排序,最后输出排序后的结果

执行 sort(result.begin(), result.end()) 时,排序的过程如下:

  1. 逐个比较字符串sort 会依次比较每两个字符串;例如,首先比较 "1 2 3""1 3 2"

    • 首先比较第一个字符 '1' 和 '1',它们相同
    • 接着比较第二个字符 ' ' 和 ' ',它们也相同
    • 然后比较字符 '2' 和 '3',因为 '2' 的 ASCII 值小于 '3',所以 "1 2 3" 会排在 "1 3 2" 前面
  2. 继续比较其他字符串:接下来会比较所有其他字符串,直到整个向量中的元素都按字典顺序排好

  3. 最终结果:经过一系列的比较和交换,result 中的元素最终按照字典顺序排列

最终输出:

假设所有栈操作序列为:

1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1

这些就是所有可能的栈操作序列,经过字典排序后输出。

总结:

通过递归,代码遍历了所有的栈操作可能性,模拟了如何从输入队列到输出队列。每次递归选择入栈或出栈,直到所有元素都被正确处理并记录下操作序列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值