Home > OS >  Reading stack pop/push operations by text-file input
Reading stack pop/push operations by text-file input

Time:05-14

I have a text file with the following contents:

2
S 8
push 2 push 3 push 5 push 7 pop print push 6 print
S 4
pop print push 1 print

An assignment gives:

The first line of the input file means the number of test cases. For each test case, the first character means which container adapter (Stack or Queue) that you need to use Linked lists to implement. The correct output should be:

The values in the stack : 2 3 5
The values in the stack : 2 3 5 6
The values in the stack :
The values in the stack : 1

I've written some working functions for stack and queue struct, though I am working on the input of the stack function first.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
void push(int);
int pop();
void printStack();

struct Stack {
    int s[100];
    int top;
    Stack() { top = -1; }
};

Stack st;

void push(int n) {
    if (st.top == 99) {
        cout << "Stack full" << endl;
    }
    else {
        st.s[  st.top] = n;
    }
}

int pop() {
    if (st.top == -1) {
        cout << "Stack is empty" << endl;
    }
    else {
        return st.s[st.top--];
    }
}

void printStack() {
    cout << "Elements";
    for (int i = 0;i <= st.top;i  ) {
        cout << st.s[i] << ' ';
    }
    cout << endl;
}

void clearStack() {
    st.top = -1;
}

The main part of the code is giving me trouble. I want to read every token of the text file while keeping the line structure; e.g. being able to parse by order of line. However, I do not know the length of each line, only the number of lines. How may I read the file correctly and finish this assignment?

int main() {

    std::ifstream file("input1.txt");
    std::string item_name;
    int numTestCases;
    vector<string> file_content{};

    while (std::getline(file, item_name))
    {
        //cout << item_name << "\n";

        char str[252];
        strcpy(str, item_name.c_str());
        char* pch;
        //cout << "str0:" << str[0] << "\n";
        file_content.push_back(str);
    }

    cout << "printing file content:" << endl;
    for (int i = 0;i < file_content.size(); i  ) {
        cout << file_content[i] << endl;
    }
}

CodePudding user response:

Okay, you basically have two distinct problems.

  1. Read your input file so you know what actions to perform.
  2. Implement both Stack and Queue.

So start by breaking them up. I looked at your stack code. Your problem says to use linked lists, which isn't what you're doing. Maybe that's just because you haven't gotten that far yet.

Code like this would give you the number of test cases.

std::string numCasesStr;
if (!getline(file, numCasesStr)) {
    cout << "early end of file detected\n";
    return;
}

int numCases = std::stoi(numCasesStr);

At this point, you can now do this:

for (int testCase = 0; testCase < numCases;   testCase) {
    std::string typeAndCountStr;
    if (!getline(file, typeAndCountStr)) {
        cout << "early end of file detected\n";
        return;
    }
    char typeC = typeAndCountStr.at(0);
    if (typeC == 'S') {
        ...
    }
    else if (typeC == 'Q') {
        ...
    }

}

The harder part is parsing the next line. You're going to get input in a similar fashion, but then you have to break it into pieces. This is called tokenizing. Basically you split it at each space. What's useful is the find method on a string.

do {
    size_t lastPos = 0;
    size_t pos = str.find(' ', lastPos);
    string thisArg; 
    if (pos != string::npos) {
         thisArg = str.substr(lastPos, pos);
         lastPos = pos   1;
    }
    else {
        thisArg = str.substr(lastPos);
    }

    // At this point, thisArg contains one argument. You still have more
    // to do, but this is one way to split your string into pieces.

} while (lastPos != string::npos);

What I do with that is stuff the individual pieces into a std::vector<std::string> and now it's a lot easier to deal with. You can traverse the vector, looking at each string, and depending upon what it is, you know if you have to grab the next item in the list (like push 8 -- you get push and then you get the 8) or just use the current item.

Overall -- break the problem down into smaller pieces. For main:

  1. Get the number of test cases

  2. Loop from 0..testCaseCnt

    • Get the type of tests (stack or queue)
    • Get the next input
    • Split it into tokens broken at each space
    • Traverse the tokens and Do The Right Thing (tm).

CodePudding user response:

Code for main to read inputs:

int main() {

    int numTestCases;
    vector<string> file_content{};

    fstream ifs;

    ifs.open("input2.txt");
    if (!ifs.is_open()) {
        cout << "Failed to open file.\n";
    }
    else {
        ifs >> numTestCases;
        char type;
        int numberOps;
        //ifs >> type;
        cout << numTestCases;

        for (int j = 0;j < numTestCases;j  ) {
            ifs >> type;
            ifs >> numberOps;
            if (type == 'S') {
                Stack st;
                clearStack();
                
                for (int i = 0;i < numberOps;i  ) {
                    string operation;
                    ifs >> operation;
                    if (operation == "push") {
                        int pushed;
                        ifs >> pushed;
                        push(pushed);
                    }
                    if (operation == "pop") {
                        pop();
                    }
                    if (operation == "print") {
                        printStack();
                    }
                }
            }
            
        }
               
        ifs.close();
    }
    

}
  • Related