Replacing the value of map elements isnt working - c++

I'm just Learning about std::map and its functions . I recently got this problem. I tried making a program which prints out a grid type data where I used std::map for the keys and values . The program prints out fine but I wanted to make a program where once I erased a data in that grid, other data above that should move down one step and the topmost would have 0 in it . somehow I tried but it doesn't seem to work . I don't know where I did wrong in that . My code:
in class header:
#pragma once
#include<iostream>
#include<string>
#include<vector>
#include<map>
#define x_Pair std::pair<unsigned int,unsigned int>
class MapCheck
{
public:
std::map<x_Pair, unsigned int>m_MapData;
void SetMapData();
x_Pair GetBlockCell(int num);
void EraseCell(int cell);
};
in class cpp:
void MapCheck::SetMapData()
{
int count = 1;
for (int j = 0; j < 20; j++)
{
for (int i = 0; i < 10; i++)
{
m_MapData[{i, j}] = count;
count++;
}
}
}
x_Pair MapCheck::GetBlockCell(int num)
{
for (int j = 0; j < 20; j++)
{
for (int i = 0; i < 10; i++)
{
if (m_MapData[{i, j}] == num)
{
return x_Pair(i, j);
}
}
}
return x_Pair(-1, -1);
}
void MapCheck::EraseCell(int cell)
{
x_Pair pair = GetBlockCell(cell);
for (int i = pair.second; i < 20; i++)
{
m_MapData[{pair.first, i}] = m_MapData[{pair.first, i - 1}];
m_MapData[{pair.first, i - 1}] = 0;
}
}
-and in main:
#include"MapCheck.h"
int main()
{
MapCheck mc;
mc.SetMapData();
std::string input;
do
{
system("cls");
for (int j = 0; j < 20; j++)
{
for (int i = 0; i < 10; i++)
{
std::cout << mc.m_MapData[{i, j}] << " ";
}
std::cout << std::endl;
}
std::cout << "Enter a number to erase or E to exit";
std::cin >> input;
mc.EraseCell(std::atoi(input.c_str()));
} while (input != "E");
return 0;
}
the output without any inputs :
after entering number 191 in the input :
expected result:
All Except the printing is fine . I dont Get Where I did Wrong. Any help would be appreciated. Thanks in advance!!

The order of
for (int i = pair.second; i < 20; i++)
{
m_MapData[{pair.first, i}] = m_MapData[{pair.first, i - 1}];
m_MapData[{pair.first, i - 1}] = 0;
}
is element found to the bottom. When you want to move everything above the item removed down one slot, this isn't all that useful. So lets flip it around.
for (int i = pair.second; i > 0; i--)
{
m_MapData[{pair.first, i}] = m_MapData[{pair.first, i - 1}];
}
m_MapData[{pair.first, 0}] = 0;
This starts at the item being removed and goes up to slot 1, copying each item down one slot. To handle the top of the column, we have m_MapData[{pair.first, 0}] = 0; to set the top item to zero, something we only need to do once.
Side note: Unless we have a sparse array, this would be a lot more efficient with a 2D array in place of the map.

You have following:
x_Pair MapCheck::GetBlockCell(int num)
which is used as
x_Pair pair = GetBlockCell(cell);
This will invoke copy constructor of std::pair<>.
I think you need to return and use reference:
x_Pair& MapCheck::GetBlockCell(int num)
which is used as
x_Pair& pair = GetBlockCell(cell);

Related

Finding two associated indexes where the sum of two elements equals a target value

Background:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
Question:
I have a list of numbers 1,2,3,4,5. My target value is 8, so I should return indices 2 and 4. My first thought is to write a a double for loop that checks to see if adding two elements from the list will get my target value. Although, when checking to see if there is such a solution, my code returns that there is none.
Here is my code:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> list;
list.push_back(1);
list.push_back(2);
list.push_back(3);
list.push_back(4);
list.push_back(5);
int target = 8;
string result;
for(int i = 0; i < list.size(); i++) {
for(int j = i+1; j < list.size(); j++) {
if(list[i] + list[j] == target) {
result = "There is a solution";
}
else {
result = "There is no solution";
}
}
}
cout << result << endl;
return 0;
}
Perhaps my approach/thinking is plain wrong. Could anyone provide any hints or suggestions to solving this problem?
Your approach is correct but you are forgetting you are in a loop that continues after finding the solution.
This will get you halfway there. I recommend putting both loops in a function, and returning once you find a match. One thing you could do is return a pair<int,int> from that function or you could simply output the results from within that point in the loop.
bool solutionFound = false;
int i,j;
for(i = 0; i < list.size(); i++)
{
for(j = i+1; j < list.size(); j++)
{
if(list[i] + list[j] == target)
{
solutionFound = true;
}
}
}
Here is what the function approach might look like:
pair<int, int> findSolution(vector<int> list, int target)
{
for (int i = 0; i < list.size(); i++)
{
for (int j = i + 1; j < list.size(); j++)
{
if (list[i] + list[j] == target)
{
return pair<int, int>(i, j);
}
}
}
return pair<int, int>(-1, -1);
}
int main() {
vector<int> list;
list.push_back(1);
list.push_back(2);
list.push_back(3);
list.push_back(4);
list.push_back(5);
int target = 8;
pair<int, int> results = findSolution(list, target);
cout << results.first << " " << results.second << "\n";
return 0;
}
Here's the C++ incorporating Dave's answer for linear execution time and a couple helpful comments:
pair<int, int> findSolution(vector<int> list, int target)
{
unordered_map<int, int> valueToIndex;
for (int i = 0; i < list.size(); i++)
{
int needed = target - list[i];
auto it = valueToIndex.find(needed);
if (it != valueToIndex.end())
{
return pair<int, int>(it->second, i);
}
valueToIndex.emplace(list[i], i);
}
return pair<int, int>(-1, -1);
}
int main()
{
vector<int> list = { 1,2,3,4,5 };
int target = 10;
pair<int, int> results = findSolution(list, target);
cout << results.first << " " << results.second << "\n";
}
You're doing this in n^2 time. Solve it in linear time by hashing each element, and checking each element to see if it's complement wrt. the total you're trying to achieve is in the hash.
E.g., for 1,2,3,4,5, with a target of 8
indx 0, val 1: 7 isn't in the map; H[1] = 0
indx 1, val 2: 6 isn't in the map, H[2] = 1
indx 2, val 3: 5 isn't in the map, H[3] = 2
indx 3, val 4: 4 isn't in the map, H[4] = 3
indx 4, val 5: 3 is in the map. H[3] = 2. Return 2,4
Code, as requested (Ruby)
def get_indices(arr, target)
value_to_index = {}
arr.each_with_index do |val, index|
if value_to_index.has_key?(target - val)
return [value_to_index[target - val], index]
end
value_to_index[val] = index
end
end
get_indices([1,2,3,4,5], 8)
Basically the same as zzxyz's most recent edit but a little quicker and dirtier.
#include <iostream>
#include <vector>
bool FindSolution(const std::vector<int> &list, // const reference. Less copying
int target)
{
for (int i: list) // Range-based for (added in C++11)
{
for (int j: list)
{
if (i + j == target) // i and j are the numbers from the vector.
// no need for indexing
{
return true;
}
}
}
return false;
}
int main()
{
std::vector<int> list{1,2,3,4,5}; // Uniform initialization Added in C++11.
// No need for push-backs of fixed data
if (FindSolution(list, 8))
{
std::cout << "There is a solution\n";
}
else
{
std::cout << "There is no solution\n";
}
return 0;
}

Selection Sort doesn't catch duplicate numbers

What i'm trying to do is implement a simple selection sort algorithm that uses the function minButGreaterThan to find the next smallest number in the array. My problem is if the array has a duplicate number, it gets passed over and left at the end. I've tried changing the controlling if statements to accommodate for this but nothing seems to work. Any advice?
double GradeBook::minButGreaterThan(double x) // - NEEDS TESTING
{
double minButGreaterThan = -1;
for (int i = 0; i < classSize; i++)
{
if (grades[i] > x)
{
minButGreaterThan = grades[i];
break;
}
}
for (int i = 0; i < classSize; i++)
{
if (grades[i] > x && grades[i] <= minButGreaterThan)
minButGreaterThan = grades[i];
}
return minButGreaterThan;
}
void GradeBook::selectionSort() //ascending order -- *DOES NOT WORK WITH DUPLICATE SCORES* - RETEST
{
double min = absoluteMin();
for (int i = 0; i < classSize; i++)
{
if (grades[i] == min)
{
double temp = grades[0];
grades[0] = grades[i];
grades[i] = temp;
break;
}
}
for (int i = 0; i < classSize-1; i++)
{
double next = minButGreaterThan(grades[i]);
for (int n = 1; n <= classSize; n++)
if (grades[n] == next)
{
double temp = grades[n];
grades[n] = grades[i+1];
grades[i+1] = temp;
}
}
}
Should work with duplicates, a selection sort just takes the minimum and moves it to the left, to the "sorted" portion of the array.
This is my implementation:
#include <algorithm>
#include <vector>
using std::swap;
using std::vector;
using std::min_element;
void selectionSort(vector<int> &v) {
for (unsigned int i = 0; i < v.size() - 1; i++) {
auto minElement = min_element(v.begin() + i, v.end());
auto minIndex = minElement - v.begin();
swap(v[i], v[minIndex]);
}
}
You might need to modify it to work with floats. Now, a double floating precision grade (double) seems too much. I think a regular float is OK.

C++ creating a forest

am new to c++ and am trying to create a burning forest simulator. I have been trying to call a function from the forest class but i dont know how to give it an argument, if anyone could help that would be great here is the code that i have at the moment.
using namespace std;
class ForestSetup
{
private:
const char Tree = '^';
const char Fire = '*';
const char emptySpace = '.';
const char forestBorder = '#';
const int fireX = 10;
const int fireY = 10;
char forest[21][21];
public:
void CreateForest()
{
// this function is to create the forest
for (int i = 0; i < 21; i++) // this sets the value of the rows from 0 to 20
{
for (int j = 0; j < 21; j++) // this sets the value of the columns from 0 to 20
{
if (i == 0 || i == 20)
{
forest[i][j] = forestBorder; // this creates the north and south of the forest border
}
else if (j == 0 || j == 20)
{
forest[i][j] = forestBorder; // this creates the east and the west forest border
}
else
{
forest[i][j] = Tree; // this filles the rest of the arrays with trees
}
}
}
forest[fireX][fireY] = Fire; // this sets the fire in the middle of the grid
}
void ShowForest(char grid[21][21])
{
for (int i = 0; i < 21; i++)
{
for (int j = 0; j < 21; j++)
{
cout << grid[i][j];
}
cout << endl;
}
}
};
int main(void)
{
ForestSetup myForest;
myForest.ShowForest();
system("Pause");
return 0;
}
Let's say you have a setOnFire function with the x and y co-ordinates of where you want to start the fire.
public:
setOnFire(int x, int y)
{
// Code to flag that part of the forest on fire
}
In your main, you would call it with
myForest.setOnFire(5,5);
Within the ForestSetup class you just need setOnFire(5,5);
This tutorials point article might help.

C++ Program crashes on passing object by value

Error occurs when I pass another object to a function -> a.Concat(b);
I have just reverted to C++ from Java for a project. When I pass object by value in this code, then an error occurs. Almost every time it is displaying a different error message, sometimes bad alloc, sometimes displaying half the output. I tried passing by reference and also made a copy constructor but both attempts failed.
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class NFA
{
public:
NFA(string);
NFA(vector<vector<string> >);
NFA Concat(NFA other_nfa);
NFA Union(NFA);
NFA KleeneStar();
void display();
int GetNFASize(){ return ALPHABET_SIZE; }
int getNoOfStates(){ return NO_OF_STATES; }
vector<vector<string> > table;
int ALPHABET_SIZE;
int NO_OF_STATES;
private:
};
NFA::NFA(string input)
{
table.resize(2);
NO_OF_STATES = 2;
for(int i = 0; i < NO_OF_STATES; i++)
{
table[i].resize(ALPHABET_SIZE + 1);
}
table[0][0] = "2";
table[0][1] = input;
table[1][0] = "3";
ALPHABET_SIZE = 3;
}
void NFA::display()
{
for(int i = 0; i < table.size(); i++)
{
for(int j = 0; j < ALPHABET_SIZE; j++)
{
cout << table[i][j] << "\t";
}
cout << endl;
}
}
NFA NFA::Concat(NFA other_nfa)
{
vector<vector<string> > ans_vector;
ans_vector.resize(ALPHABET_SIZE + other_nfa.ALPHABET_SIZE);
for(int i = 0; i < NO_OF_STATES; i++)
{
for(int j = 0; j < ALPHABET_SIZE; j++)
{
ans_vector[i][j] = table[i][j];
}
}
for(int i = other_nfa.NO_OF_STATES - 1; i < other_nfa.NO_OF_STATES; i++)
{
for(int j = 0; j < other_nfa.ALPHABET_SIZE; j++)
{
ans_vector[i][j] = other_nfa.table[i][j];
}
}
ans_vector[NO_OF_STATES - 1][3] = other_nfa.table[0][0];
NFA ansNFA(ans_vector);
}
NFA::NFA(vector<vector<string> >)
{
}
int main()
{
NFA a("a");
a.display();
NFA b("b");
b.display();
NFA ab = a.Concat(b);
system("pause");
return 0;
}
In
NFA::NFA(string input)
{
table.resize(2);
NO_OF_STATES = 2;
for(int i = 0; i < NO_OF_STATES; i++)
{
table[i].resize(ALPHABET_SIZE + 1);
}
table[0][0] = "2";
table[0][1] = input;
table[1][0] = "3";
ALPHABET_SIZE = 3;
}
You variable initializations are out of order. When you use
table[i].resize(ALPHABET_SIZE + 1);
ALPHABET_SIZE contains garbage as you have not set a value yet. Just move ALPHABET_SIZE = 3; before the for loop and you should be okay.
I would also suggest you use a member initialization list for all variables to you can. In this case your constructor would look like
NFA::NFA(string input) : NO_OF_STATES(2), ALPHABET_SIZE(3)
{
table.resize(2);
for(int i = 0; i < NO_OF_STATES; i++)
{
table[i].resize(ALPHABET_SIZE + 1);
}
table[0][0] = "2";
table[0][1] = input;
table[1][0] = "3";
}
You resize a vector<vector<string> but fail to resize any of the contained vectors:
ans_vector.resize(ALPHABET_SIZE + other_nfa.ALPHABET_SIZE);
And then later you index into the nested vectors, which goes out of bounds:
for(int i = 0; i < NO_OF_STATES; i++)
{
for(int j = 0; j < ALPHABET_SIZE; j++)
{
ans_vector[i][j] = table[i][j];
}
}
You'll need to call resize for every vector inside ans_vector, or use push_back, emplace_back etc, which would probably be safer for you.
AlPHABET_SIZE is not defined in:
table[i].resize(ALPHABET_SIZE + 1);
by default, it contains some garbage value. This might be your problem.
NFA::NFA(string input)
{
table.resize(2);
NO_OF_STATES = 2;
for(int i = 0; i < NO_OF_STATES; i++)
{
table[i].resize(ALPHABET_SIZE + 1);
}
table[0][0] = "2";
table[0][1] = input;
table[1][0] = "3";
ALPHABET_SIZE = 3;
}
ALPHABET_SIZE is being used in the ctor of NFA though it was not initialized. it causes weird behaviour.
You are creating three objects a,b,ab. during construction of the object program crashes. it has nothing to do with pass by reference/value or using copy ctor.
From the first look I would say the problem lays in the vector-access of table, which would go out-of-range.
From design-point, several issues:
It seems you _other_nfa can be declared const reference:
NFA NFA::Concat(const NFA& other_nfa)
There is no return. At the end of your Concat method there should be sth. like:
return ansNFA;
It seems within Concat you don't change your member variables like table (which btw. is no good name for a member-variable). If Concat dosn't change the class members, you should declare it const:
NFA NFA::Concat(const NFA& other_nfa) const

How do I properly implement a display function of a class?

I have a class called magicSquare with a constructor and a display function called display. The constructor creates the magic square, and the display function displays the results. In my main function, I created an instance of magicSquare called ms and gave it a value 7. To display it, shouldn't it work if I just did ms.display()?
class magicSquare
{
private:
int size, square;
vector<vector <int> > finalvec;
public:
magicSquare(int a):finalvec(a, std::vector<int>(a))
{
int i = 0;
int j = a/2;
size = a;
square = a * a;
vector<int>vec(a);
vector<vector<int> > finalvec(a,vec);
for (int i = 0; i < size; i++)
{
for (int j = 0; j< size; j++)
cout << finalvec[i][j];
cout << endl;
}
for (int k=0; k < square; ++k)
{
finalvec[i][j] = k;
i--;
j++;
if (k%a == 0)
{
i = i+ 2;
--j;
}
else
{
if (j==a)
j = j- a;
else if (i<0)
i = i+ a;
}
}
}
void display()
{
for (int i = 0; i < size; i++)
{
for (int j = 0; j< size; j++)
cout << finalvec[i][j];
cout << endl;
}
}
};
int main()
{
magicSquare ms(3);
ms.display();
return 0;
}
Your Error
As pointed by #Retired Ninja, the vector > finalvec(a,vec); hide your member variable finalvec, as you redefine it as a new vector...
What can correct it
You could construct your vector inside a Member initializer list like this
magicSquare(int a) : finalvec(a, std::vector<int>(a, 0)) {
/* your constructor */
}
And delete the two line:
vector<int>vec(a);
vector<vector<int> > finalvec(a,vec);
In your code
How to not make this error
Seeing which value are a class member, method parameter or even context variable can be sometime difficult:
What i can recommend you is to do the following:
class member -> m_NAME_OF_YOUR_CLASS_MEMBER
method parameter -> t_NAME_OF_YOUR_METHODE_PARAMETER
context variable -> c_NAME_OF_YOUR_CONTEXT_VARIABLE
by doing this error like you've done is a bit harder to do!
EDIT: After testing your code
I see there's error in it, effectively, the first time you go in that line:
finalvec[i][j] = k;
i > size, so you access further that your vector allow it, which result in a segfault! please repair your code!
hope that can help