Further optimization of finding max in a stack - c++

My problem is to insert an element, pop the last inserted element and printed the max in the given. I am using 2 stacks for the purpose and it is optimized based on most suggested techniques available. But I still need further optimization for the case where number of queries, q <=100000 and test cases<=100. The following is my code as of now:
int main() {
int t,q;
cin>>t;
char query;
int detail;
for(int test=0;test<t;test++)
{
cout<<"Case "<<test+1<<":\n";
cin>>q;
stack<int> s;
stack<int> max;
for(int i=0;i<q;i++)
{
cin>>query;
if(query=='A')
{
cin>>detail;
s.push(detail);
if(max.empty())
max.push(detail);
else if(detail>=max.top())
max.push(detail);
}
else if(query=='R')
{
if(!s.empty())
{
if(s.top()==max.top())
max.pop();
s.pop();
}
}
else
{
if(max.empty())
cout<<"Empty\n";
else
cout<<max.top()<<"\n";
}
}
}
return 0;
}

I'm not sure what do you mean by 'optimize' (minimize memory usage in your cases, improve execution time or just referring to algorithm efficiency). Following comment from #alexeykuzmin0 , the code would look as follows:
std::stack<std::pair<int, int>> stack;
for (int i = 0; i<q; i++)
{
std::cin >> query;
if (query == 'A')
{
std::cin >> detail;
int max = stack.empty() ? detail : std::max(detail, stack.top().second);
stack.push(std::make_pair(detail, max));
}
else if (query == 'R')
{
if (!stack.empty())
{
stack.pop();
}
}
else
{
if (stack.empty())
std::cout << "Empty\n";
else
std::cout << stack.top().second << "\n";
}
}
Additionally it looks like you're not using the history of inserted items for anything, thus we can remove the pair and solve it using single stack.
std::stack<int> stack;
for (int i = 0; i<q; i++)
{
std::cin >> query;
if (query == 'A')
{
std::cin >> detail;
int max = stack.empty() ? detail : std::max(detail, stack.top());
stack.push(max);
}
else if (query == 'R')
{
if (!stack.empty())
{
stack.pop();
}
}
else
{
if (stack.empty())
std::cout << "Empty\n";
else
std::cout << stack.top() << "\n";
}
}
Also remember to measure performance (timings) in release mode builds, with optimizations on. (don't measure performance on debug builds)

Related

Stack Program in C++

I want to implement a code in my program where it guesses whether or not the given series of operations and corresponding return values from an input file are operating as a stack. In other words, the output is fully determined by the input file.
The text file (StackTest.txt):
4
INSERT 2
INSERT 1
REMOVE 1
REMOVE 2
6
INSERT 5
INSERT 10
INSERT 12
REMOVE 10
REMOVE 5
REMOVE 12
2
INSERT 8
REMOVE 8
Expected Output(from input file):
stack
not stack
stack
However, I'm stuck on how to implement this feature into my current code.
If anyone can help me out on how to achieve the expected output above or give me some hints, I would really appreciate it!
Code in progress...
#include <iostream>
#include <fstream>
#include <string>
#include <stack>
using namespace std;
// Function to check validity of stack sequence
bool validStackSeq(string input, int len)
{
// maintain count of popped elements
int j = 0;
// an empty stack
stack <int> s;
for(int i = 0; i < len; i++)
{
s.push(input[i]);
// check if appended value is next to be popped out
while (!s.empty() && j < len && s.top() == input[j])
{
s.pop();
j++;
}
}
return j == len;
}
int main()
{
ifstream inFile;
string data;
string command;
int num;
inFile.open("StackTest.txt");
//cout << "Reading file..." << endl;
stack <int> s;
while(getline(inFile, data))
{
if(command == "INSERT")
{
s.push(num);
}
else if(command == "REMOVE")
{
s.pop();
}
num = sizeof(data)/sizeof(data[0]);
cout << (validStackSeq(data, num) ? "Stack" : "Not Stack") << endl;
}
inFile.close();
}
Current Output
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack
Stack Validation Program (without input file)
#include <iostream>
#include <stack>
using namespace std;
bool validStackSeq(int pushed[], int popped[], int len)
{
int j = 0;
stack <int> pt;
for(int i = 0; i < len; i++)
{
pt.push(pushed[i]);
while (!pt.empty() && j < len && pt.top() == popped[j])
{
pt.pop();
j++;
}
}
return j == len;
}
// Driver code
int main()
{
int pushed[] = {2, 1};
int popped[] = {1, 2};
int len = sizeof(pushed)/sizeof(pushed[0]);
int pushed1[] = {5, 10, 12};
int popped1[] = {12, 5, 10};
int len1 = sizeof(pushed1)/sizeof(pushed1[0]);
int pushed2[] = {8};
int popped2[] = {8};
int len2 = sizeof(pushed2)/sizeof(pushed2[0]);
int pushed3[] = {1, 4};
int popped3[] = {4};
int len3 = sizeof(pushed3)/sizeof(pushed3[0]);
cout << (validStackSeq(pushed, popped, len) ? "Stack" : "Not Stack") << endl;
cout << (validStackSeq(pushed1, popped1, len1) ? "Stack" : "Not Stack") << endl;
cout << (validStackSeq(pushed2, popped2, len2) ? "Stack" : "Not Stack") << endl;
cout << (validStackSeq(pushed3, popped3, len3) ? "Stack" : "Not Stack") << endl;
return 0;
}
Perform the INSERT and REMOVE operations as specified in the text file. The result is 'stack' if all remove operations are possible (do not occur when the stack is empty) and the operand of each remove operation equals the actual value poped from your stack.
UPDATED 2020-02-29
You cannot create two separate arrays for INSERT and REMOVE operations and process them independently, because the result depends on how the operations are interleaved. For example
INSERT 1
INSERT 2
REMOVE 2
REMOVE 1
should result in stack, but if we move one REMOVE operation up:
INSERT 1
REMOVE 2
INSERT 2
REMOVE 1
the result will become not stack. It means that you need to process the operations in exactly same order as they appear in the file.
The general structure of the code:
ifstream inFile;
inFile.open("StackTest.txt");
int num;
while (inFile >> num) { // Read number of INSERT/REMOVE in each test set
stack<int> s;
bool isStack = true;
for (int i = 0; i < num; i++) {
// Read and process all INSERT/REMOVE operations in this test set
// Set isStack to false if not stack behavior detected
}
cout << (isStack ? "stack" : "not stack") << endl;
}
inFile.close();
As we read the operations from the input file we try to perform them. The INSERT operations should be performed as-is, no checks are required.
if (operation == "INSERT") {
s.push(argument);
}
The REMOVE operations require two checks to be performed: whether the stack is empty and whether the top of stack contains the same number as the argument of the REMOVE operation. If either of the checks fail then we set isStack to false.
if (operation == "REMOVE") {
if (s.empty() || s.top() != argument) {
isStack = false;
}
if (!s.empty()) {
s.pop ();
}
}
Combining this together we get:
#include <iostream>
#include <fstream>
#include <string>
#include <stack>
using namespace std;
int main () {
ifstream inFile;
inFile.open("StackTest.txt");
int num;
while (inFile >> num) {
stack<int> s;
bool isStack = true;
for (int i = 0; i < num; i++) {
string operation;
int argument;
inFile >> operation >> argument;
if (!isStack)
continue;
if (operation == "INSERT") {
s.push(argument);
}
else if (operation == "REMOVE") {
if (s.empty() || s.top() != argument) {
isStack = false;
}
if (!s.empty()) {
s.pop ();
}
}
}
cout << (isStack ? "stack" : "not stack") << endl;
}
inFile.close();
}
There is just one more thing to mention: after we read the operation name and its argument from the file we do a check
if (!isStack)
continue;
This statement is not required, it's there just for a performance improvement. If we already detected that the given test set does not correspond to a stack then we don't need to perform all the remaining operations in this test set, we just skip them. You can safely remove this statement without influencing the result.

Code only outputs std::vector one time instead of wanted multiple times

So my problem is the following: I want to program a basic game of life simulation. Therefore I am using std::vector to save the current state and calculate the next state. All put together in a while(). I am doing std::cout for every value, formated as a matrix. The problem is, that I only get one "matrix" as an output, instead of expected multiple.
I've also tried to output text after calculating the next state (so before and after the nextCells=currentCells), which didn't work, while outputting text within the calculating for() loop works.
I don't know what to do anymore. Appreciate any kind of help!
I've tried to output text after calculating the next state (so before and after the nextCells=currentCells), which didn't work, while outputting text within the calculating for() loop works.
#include <iostream>
#include <vector>
#include <unistd.h>
#define DIMX 10
#define DIMY 10
int countCells(std::vector<std::vector<int>> currentGrid, int x, int y);
int main() {
std::vector<std::vector<int>> currentCells(DIMX, std::vector<int>(DIMY));
std::vector<std::vector<int>> nextCells(DIMX, std::vector<int>(DIMY));
int count = 0;
nextCells = currentCells;
while(true) {
count++;
for(int i=0;i<=DIMX-1;i++) {
for(int j=0;j<=DIMY-1;j++) {
std::cout << currentCells[i][j];
std::cout.flush();
}
std::cout << "\n";
}
for(int i=0;i<=DIMX-1;i++) {
for(int j=0;j<=DIMY-1;j++) {
int aliveCells = countCells(currentCells, i, j);
if(currentCells[i][j]==0) {
if(aliveCells==3) {
nextCells[i][j]=1;
} else {
nextCells[i][j]=0;
}
} else {
if(aliveCells>3) {
nextCells[i][j]=0;
} else if(aliveCells<2) {
nextCells[i][j]=0;
} else {
nextCells[i][j]=1;
}
}
}
}
currentCells = nextCells;
if(count>=5) {
return 0;
}
}
}
int countCells(std::vector<std::vector<int>> currentGrid, int x, int y) {
int aliveCounter;
if(x==DIMX || x==0 || y==DIMY || y==0) {
return 0;
}
if(currentGrid[x-1][y-1]==1) {
aliveCounter++;
} else if(currentGrid[x-1][y]==1) {
aliveCounter++;
} else if(currentGrid[x-1][y+1]==1) {
aliveCounter++;
} else if(currentGrid[x][y-1]==1) {
aliveCounter++;
} else if(currentGrid[x][y+1]==1) {
aliveCounter++;
} else if(currentGrid[x+1][y-1]==1) {
aliveCounter++;
} else if(currentGrid[x+1][y]==1) {
aliveCounter++;
} else if(currentGrid[x+1][y+1]==1) {
aliveCounter++;
}
return aliveCounter;
}
Your code produces an out of vector-range exception, For optimization reasons the exception may not throw in release mode.
When countCells gets called for y = 9 or x = 9
currentGrid[x+1][y+1]
is out of range.
Notice that
v = std::vector<int>(10,0) can be called from v[0] to v[9]; not v[10],
which would be out of range.

How can I trace back the error

I was assigned to create an array check (to see if the array is increasing, decreasing, or neither [then exiting if neither]) and a recursive binary search for one of my assignments. I was able to do these things after some help from my peers, but I need help in finding what seems to be causing the error
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Aborted
when running the code. I Googled this error and this error seems to be vague or I just am not understanding. It compiles without errors, but I need help in what finding what I did wrong. It is able to run without the binarySearchR function and its associating code, as the array check on its own was the previous assignment. Below is the code, and I thank you so much in advance!
#include <iosteam>
#include <string>
#include <cstdlib>
#include <fstream>
using namespace std;
int checkArraySort (string *fileLines, int numberOfLines);
int binarySearchR (string *fileLines, string searchKey, int iMin, int iMax);
int main ()
{
int numberOfLines = 0;
string searchKey = 0;
cout << "Input search key: ";
cin >> searchKey;
ifstream fileIn;
fileIn.open("words_in.txt");
string line;
if (fileIn.eof()) /* Checks file to see if it is blank before proceeding */
{
exit (EXIT_SUCCESS);
}
else
{
while(!(fileIn.eof()))
{
fileIn >> line;
numberOfLines++;
}
fileIn.close(); /* closes fileIn, need to reopen to reset the line location */
fileIn.open("words_in.txt");
string *fileInLines;
fileInLines = new string[numberOfLines];
for (int i = 0; i < numberOfLines; i++)
{
fileIn >> line;
fileInLines[i] = line;
}
fileIn.close(); /* closes fileIn */
int resultingCheck = checkArraySort(fileInLines, numberOfLines);
if (resultingCheck == -1)
{
cout << "The array is sorted in descending order." << endl;
}
else if (resultingCheck == 1)
{
cout << "The array is sorted in ascending order." << endl;
}
else
{
cerr << "ERROR: Array not sorted!" << endl;
exit (EXIT_FAILURE);
}
int searchResult = binarySearchR (fileInLines, searchKey, 0, numberOfLines);
if (!searchResult == -1)
{
cout << "Key found at index " << searchResult << "." << endl;
}
else
{
cout << "Key not found at any index." << endl;
}
exit (EXIT_SUCCESS);
}
}
int checkArraySort (string *fileLines, int numberOfLines)
{
int result = 1; /* Ascending by default */
for (int i = 1; i < numberOfLines; i++) /* Checks if decending */
{
if (fileLines[i] < fileLines[i-1])
{
result = -1;
}
}
if (result == -1) /* Makes sure it is descending (or if it is neither) */
{
for (int i = 1; i < numberOfLines; i++)
{
if (fileLines[i] > fileLines[i-1])
{
result = 0;
}
}
}
return result;
}
int binarySearchR (string *fileLines, string searchKey, int iMin, int iMax)
{
// so, its gotta look at the center value and each times, it discards half of the remaining list.
if (iMax < iMin) /* If the minimum is greater than the maximum */
{
return -1;
}
else
{
int iMid = (iMin + iMax) / 2;
if (fileLines[iMid] > searchKey) /* If the key is in the lower subset */
{
return binarySearchR (fileLines, searchKey, iMin, iMid - 1);
}
else if (fileLines[iMid] < searchKey) /*If the key is in the upper subset */
{
return binarySearchR (fileLines, searchKey, iMin, iMid + 1);
}
else /*If anything else besides the two */
{
return iMid;
}
}
}
The easy way: add a bunch of cout s to see where you program goes and what the values are.
Pros
Easy to do
Cons
Requires a recompile each time you want to add more info
The hard way: Learn to use a debugger
Pros
Can inspect "on the fly"
Don't need to rebuild
Can use what you learn in every other C++ program
Cons
Requires a bit of research to learn how to do it.

Nested for loop being ignored after if-else chain

I am programming a MARIE assembler for one of my classes and I've ran into a logical error involving my control structure for one of my functions.
What I'm trying to accomplish is taking in all the data that was inserted into my vectors and then that data is being used to create integer opcode data for display. Yet for whatever reason my nested for loop is being ignored after my if-else chain.
The code within the nested for-loop seems to be working properly aside from this one logic error.
Please note that instructions, hexNums, secondPassData, valueZ, and symBols are my vectors.
For some clarification:
The If-Else chain is just used to read instruction words and to set basedInt to the proper decimal number for later hexadecimal conversion.
There are a few special conditions in the code below which are marked.
If there is no special condition then the code checks the valueZ vector at instructions.at(i) to see if the valueZ element is in symBols.
If it is a symBol element through character checks, it takes its hexNums position and adds it to the basedInt.
If it is not, it instead has its corresponding valueZ element converted from string to int and then added to the basedInt.
Those elements are added to the secondPassData vector.
int basedInt;
int newInt;
int pushInt;
string temp;
for(unsigned int i = 0; i < instructions.size(); ++i) //if i is less then instructions.size(), follow through with the statement
{
if(instructions.at(i) == "JNS") //sets basedInt to a decimal version of its hexidecimal opcode
{
basedInt = 0;
}
else if(instructions.at(i) == "HALT") //a special condition where the number is plugged into the secondPassData vector automatically
{
secondPassData.push_back(28672);
continue;
}
else if(instructions.at(i) == "CLEAR") //same as above
{
secondPassData.push_back(-24576);
continue;
}
else if(instructions.at(i) == "ADDL")
else if(instructions.at(i) == "ORG")
{
secondPassData.push_back(0000);
continue;
}
else if(instructions.at(i) == "HEX") //checks for the HEX psuedo-OP.
{
temp = valueZ.at(i); //converts it at position i to a string
basedInt = atoi(temp.c_str()); //converts that string to an int.
secondPassData.push_back(basedInt);//pushes into vector.
continue;
}
else if(instructions.at(i) == "DEC")
{
temp = valueZ.at(i);
basedInt = atoi(temp.c_str()); //similar function as above.
secondPassData.push_back(basedInt);
continue;
}
else
{
cout << "Beep Boop, program borked!" << endl;
return;
}
//for some reason the code below is getting ignored.
cout << i << endl;
for(unsigned int a = 0; a < instructions.size(); ++a) //works
{
cout << i << " " << a << endl;
string valFind = valueZ.at(i);
string symFind = symBols.at(a); //works
temp = valueZ.at(i);
if(symFind[0] == valFind[0])
{
newInt = hexNums.at(a);
pushInt = basedInt + newInt;
secondPassData.push_back(pushInt);
break;
}
else if(symFind[0] != valFind[0]) //works
{
temp = valueZ.at(i);
newInt = atoi(temp.c_str()); //works
pushInt= basedInt + newInt;
secondPassData.push_back(pushInt); //works
break;
}
break;
}
}
If you hit a continue in your else-if chain your main for loop will jump to its next iteration and will skip the rest of your code (in this case your nested for loop)
continue

C++ Member Function Clearing Matrix

I have had a similar issue with quite a few projects I have worked on involving classes containing arrays. I have a class that is supposed to handle a 2 dimensional matrix representing a TicTacToe game. There is an enumeration in the class for the status of the current game and one member function that has an enumeration return type. I cant seem to figure out why I can create the class set values in the matrix and as soon as I call the member function with the enumerated return type the whole array is reinitialized to 0. I think it has something to do with the constructor being called again or something along those lines but I have not been able to find anything after searching for the past few hours. Any help would be greatly appreciated.
Here is my header file containing the class information:
#ifndef TTT_H
#define TTT_H
#include <cstdlib>
#include <iostream>
using namespace std;
class TicTacToe
{
private:
enum Status{WinX, WinO, Continue, Draw};
int **board;
public:
TicTacToe();
~TicTacToe();
void PrintBoard();
bool ValidMove(int, int);
bool PlayerMove(int, int, int);
Status GameStatus(); //this one causes the problem
void Debug();
};
#endif
Here is the code for CPP file with the member function definitions:
#include "TicTacToe.h"
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cassert>
using namespace std;
TicTacToe::TicTacToe()
{
board = new int*[3];
assert(board != 0);
for(int i=0;i<3;i++)
{
cout << "Constructor Ran again" << endl; //for testing
board[i] = new int[3];
assert(board[i] != 0);
for(int j=0;j<3;j++)
board[i][j] = 9;
}
}
TicTacToe::TicTacToe(TicTacToe &copy)
{
board = new int*[3];
assert(board != 0);
}
TicTacToe::~TicTacToe()
{
if(board)
delete[] board;
}
void TicTacToe::PrintBoard()
{
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
{
cout << "| ";
switch(board[i][j]){
case 0:
cout << "O ";
break;
case 1:
cout << "X ";
break;
case 9:
cout << " ";
break;
}
}
cout << "|" << endl;
cout << "------------" << endl;
}
}
bool TicTacToe::ValidMove(int row, int col)
{
bool valid = false;
if(row < 3 && col < 3)
{
if(board[row][col] == 9)
valid = true;
}
return valid;
}
bool TicTacToe::PlayerMove(int player, int row, int col)
{
bool done = false;
if(ValidMove(row,col) == true)
{
if(player == 1)
board[row][col] = 1;
else
board[row][col] = 0;
done = true;
}
return done;
}
TicTacToe::Status TicTacToe::GameStatus() //This function is the problem
{
int check, empty = 0;
bool done = false;
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
{
check += board[i][j];
if(board[i][j] = 9)
empty++;
}
if(check == 0)
return WinO;
else if(check == 3)
return WinX;
check = 0;
}
if(empty == 0)
return Draw;
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
check += board[j][i];
if(check == 0)
return WinO;
else if(check == 3)
return WinX;
check = 0;
}
check = board[0][0] + board[1][1] + board[2][2];
if(check == 0)
return WinO;
else if(check == 3)
return WinX;
check = 0;
check = board[0][2] + board[1][1] + board[2][0];
if(check == 0)
return WinO;
else if(check == 3)
return WinX;
check = 0;
return Continue;
}
void TicTacToe::Debug()
{
//cout << &board[0][0] << endl;
for(int i=0;i<3;++i)
{
for(int j=0;j<3;++j)
cout << board[i][j];
cout << endl;
}
}
Here is the driver file I am using to test:
#include "TicTacToe.h"
#include <iostream>
#include <cassert>
using namespace std;
int main()
{
int row, col;
bool valid;
enum Status{WinX, WinO, Continue, Draw};
TicTacToe * T;
T = new TicTacToe;
assert(T != 0);
cout << "There are 2 players. P1 is x P2 is o" << endl;
do
{
T->PrintBoard();
valid = false;
while(valid == false)
{
cout << "\nP1 choose a cell" ;
cin >> row >> col;
if(T->ValidMove(row, col) == true)
{
T->PlayerMove(1, row, col);
valid = true;
}
else
{
cout << "Not a valid choice" << endl;
valid = false;
}
}
T->PrintBoard();
cout << endl;
T->GameStatus(); //<<<<<this is the pain in my butt
T->PrintBoard();
valid = false;
while(valid == false)
{
cout << "\nP2 choose a cell" ;
cin >> row >> col;
if(T->ValidMove(row, col) == true)
{
T->PlayerMove(2, row, col);
valid = true;
}
else
{
cout << "Not a valid choice" << endl;
valid = false;
}
}
}
while(/*T->GameStatus() == Continue*/ 1==1);
//the call to GameStatus was commented out of the
//while statement for testing
return 0;
}
I know the code inside of the GameStatus function is far from pretty but the array is messed up before any of those lines are processed.
I left all of the other functions just to show that they work properly without issue.
Thanks in advance for any help you may be able to give.
You've got a simple typo in your code..
if(board[i][j] = 9) // will always return true (refp)
empty++;
Other remarks
When looking at your code a bit more thoroughly I see that you have a few other miss-happens, intentional or unintentional.. that I don't know:
int check is not initialized in TicTacToe::GameStatus
You are not freeing the allocated memory properly, you'll
need to free all entries in board, ie. delete board[i])
I don't like bugs, how can I get rid of the operator= vs operator== problem?
A quite common method to circumvent the problem of making a typo and writing = when you mean to compare (==) two variables is to flip the operands around (if one of them is a constant value, such as 9.
if(9 = board[i][j]) will not compile and such a bug would've never appeared in your code.
I'll have to say that I don't like writing my statements that way.. though it's a quite common method, especially in the "beginner" segment.
check is not initialized in GameStatus() .
if (board[i][j] = 9)
Isn't the above line of code resetting the array contents? You probably want to use == here, instead.
You have a serious issue in memory management. Look:
Your constructor performs 4 allocations (an array of pointers and 3 arrays of ints, to emulate a 2D arrray),
Your destructor performs 1 deallocation (= memory leak),
You have a custom destructor but you don't define (or block) operator= (you need to, see What is The Rule of Three?)
Your copy constructor is incomplete and doesn't create a "valid" object.
Basically the above is likely to cause you some memory problems. I suggest to:
Rewrite the destructor to first free all the arrays of ints, then the array of pointers,
Make the class TicTacToe uncopiable by declaring the copy constructor and the operator= as private.
Also some minor details on that matter:
board = new int*[3];
assert(board != 0);
The assertion is unnecessary. If the allocation fails, the operator new will throw an exception.
if(board)
delete[] board;
Operators delete and delete[] don't do anything if their argument is a null pointer, so that condition is redundant. Also you have designed your object with the invariant that the board exists as long as the TicTacToe object exists, so that check is totally unnecessary, right?
Keep it safe and simple!