I have a list of {a,b} and i need all possible combinatations where say n=3.
so:
[a,b,a],
[b,a,b]
[a,a,a]
[b,b,b]
etc.
Is there a name of such a problem
My current solution just uses random sampling and is very inefficient:
void set_generator(const vector<int>& vec, int n){
map<string, vector<int>> imap;
int rcount = 0;
while(1){
string ms = "";
vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
cout << ms << endl;
}
}
set_generator({1,2},3);
Let us call b the size of the input vector.
The problem consists in generating all numbers from 0 to b^n - 1, in base b.
A simple solution increments the elements of an array one by one, each from 0 to b-1.
This is performed by the function increment in the code hereafter.
Output:
111
211
121
221
112
212
122
222
The code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
void set_generator_op (const std::vector<int>& vec, int n){
std::map<std::string, std::vector<int>> imap;
int rcount = 0;
while(1){
std::string ms = "";
std::vector<int> mset;
for(int i=0; i<n; i++){
int sampled_int = vec[rand() % vec.size()];
ms += std::to_string(sampled_int);
mset.emplace_back(sampled_int);
}
if(rcount > 100)
break;
if(imap.count(ms)){
rcount += 1;
//cout << "*" << endl;
continue;
}
rcount = 0;
imap[ms] = mset;
std::cout << ms << "\n";
}
}
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
void set_generator_new (const std::vector<int>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
while (true) {
std::string permut = "";
for (auto &k: cpt) {
permut += std::to_string (vec[k]);
}
std::cout << permut << "\n";
if (!increment(cpt, base)) return;
}
}
int main() {
set_generator_op ({1,2},3);
std::cout << "\n";
set_generator_new ({1,2},3);
}
Following advices of Jarod42, I have
suppressed the useless conversion to a string
used a more elegant do ... while instead of the while true
inversed the iterators for printing the result
Moreover, I have created a templated version of the program.
New output:
111
112
121
122
211
212
221
222
aaa
aab
aba
abb
baa
bab
bba
bbb
And the new code:
#include <iostream>
#include <vector>
#include <string>
#include <map>
// incrementation of a array of int, in base "base"
// return false if max is already attained
bool increment (std::vector<int>& cpt, int base) {
int n = cpt.size();
for (int i = 0; i < n; ++i) {
cpt[i]++;
if (cpt[i] != base) {
return true;
}
cpt[i] = 0;
}
return false;
}
template <typename T>
void set_generator_new (const std::vector<T>& vec, int n){
int base = vec.size();
std::vector<int> cpt (n, 0);
do {
for (auto it = cpt.rbegin(); it != cpt.rend(); ++it) {
std::cout << vec[*it];
}
std::cout << "\n";
} while (increment(cpt, base));
}
int main() {
set_generator_new<int> ({1,2}, 3);
std::cout << "\n";
set_generator_new<char> ({'a','b'}, 3);
}
Besides the concrete answer for integer usage, I want to provide a generic way I needed during test case construction for scenarios with a wide spread of various parameter variations. Maybe it's helpful to you too, at least for similar scenarios.
#include <vector>
#include <memory>
class SingleParameterToVaryBase
{
public:
virtual bool varyNext() = 0;
virtual void reset() = 0;
};
template <typename _DataType, typename _ParamVariationContType>
class SingleParameterToVary : public SingleParameterToVaryBase
{
public:
SingleParameterToVary(
_DataType& param,
const _ParamVariationContType& valuesToVary) :
mParameter(param)
, mVariations(valuesToVary)
{
if (mVariations.empty())
throw std::logic_error("Empty variation container for parameter");
reset();
}
// Step to next parameter value, return false if end of value vector is reached
virtual bool varyNext() override
{
++mCurrentIt;
const bool finished = mCurrentIt == mVariations.cend();
if (finished)
{
return false;
}
else
{
mParameter = *mCurrentIt;
return true;
}
}
virtual void reset() override
{
mCurrentIt = mVariations.cbegin();
mParameter = *mCurrentIt;
}
private:
typedef typename _ParamVariationContType::const_iterator ConstIteratorType;
// Iterator to the actual values this parameter can yield
ConstIteratorType mCurrentIt;
_ParamVariationContType mVariations;
// Reference to the parameter itself
_DataType& mParameter;
};
class GenericParameterVariator
{
public:
GenericParameterVariator() : mFinished(false)
{
reset();
}
template <typename _ParameterType, typename _ParameterVariationsType>
void registerParameterToVary(
_ParameterType& param,
const _ParameterVariationsType& paramVariations)
{
mParametersToVary.push_back(
std::make_unique<SingleParameterToVary<_ParameterType, _ParameterVariationsType>>(
param, paramVariations));
}
const bool isFinished() const { return mFinished; }
void reset()
{
mFinished = false;
mNumTotalCombinationsVisited = 0;
for (const auto& upParameter : mParametersToVary)
upParameter->reset();
}
// Step into next state if possible
bool createNextParameterPermutation()
{
if (mFinished || mParametersToVary.empty())
return false;
auto itPToVary = mParametersToVary.begin();
while (itPToVary != mParametersToVary.end())
{
const auto& upParameter = *itPToVary;
// If we are the very first configuration at all, do not vary.
const bool variedSomething = mNumTotalCombinationsVisited == 0 ? true : upParameter->varyNext();
++mNumTotalCombinationsVisited;
if (!variedSomething)
{
// If we were not able to vary the last parameter in our list, we are finished.
if (std::next(itPToVary) == mParametersToVary.end())
{
mFinished = true;
return false;
}
++itPToVary;
continue;
}
else
{
if (itPToVary != mParametersToVary.begin())
{
// Reset all parameters before this one
auto itBackwd = itPToVary;
do
{
--itBackwd;
(*itBackwd)->reset();
} while (itBackwd != mParametersToVary.begin());
}
return true;
}
}
return true;
}
private:
// Linearized parameter set
std::vector<std::unique_ptr<SingleParameterToVaryBase>> mParametersToVary;
bool mFinished;
size_t mNumTotalCombinationsVisited;
};
Possible usage:
GenericParameterVariator paramVariator;
size_t param1;
int param2;
char param3;
paramVariator.registerParameterToVary(param1, std::vector<size_t>{ 1, 2 });
paramVariator.registerParameterToVary(param2, std::vector<int>{ -1, -2 });
paramVariator.registerParameterToVary(param3, std::vector<char>{ 'a', 'b' });
std::vector<std::tuple<size_t, int, char>> visitedCombinations;
while (paramVariator.createNextParameterPermutation())
visitedCombinations.push_back(std::make_tuple(param1, param2, param3));
Generates:
(1, -1, 'a')
(2, -1, 'a')
(1, -2, 'a')
(2, -2, 'a')
(1, -1, 'b')
(2, -1, 'b')
(1, -2, 'b')
(2, -2, 'b')
For sure, this can be further optimized/specialized. For instance you can simply add a hashing scheme and/or an avoid functor if you want to avoid effective repetitions. Also, since the parameters are held as references, one might consider to protect the generator from possible error-prone usage via deleting copy/assignement constructors and operators.
Time complexity is within the theoretical permutation complexity range.
Related
I'm writing a code that tries to paint all dots in graph correctly by randomly giving colors (according to some simple algorithm) while I still have time left. Correctly means that no two dots with same color are adjacent. Also every dot must have color distinct from the initial.
I noticed that in a simple test it gives wrong answer when I set time limit <=3 sec, but it doesn't work 3 seconds, it almost instantly throws "Impossible", here is part of the code (start, end and tl are global):
std::string new_paint;
bool success = false;
while (!success && end - start < tl) {
std::time(&end);
new_paint = TryPaint(edges, paint, success, v);
}
if (success) {
for (int i = 1; i < new_paint.size(); ++i) {
std::cout << new_paint[i];
}
} else {
std::cout << "Impossible";
}
Test is:
3 3
RGB
1 2
2 3
1 3
It means "3 dots with 3 edges, initial color RGB, edges between 1 2, 1 3 and 2 3"
Also I noticed that when i try to cout end - start it gives 6 in this test. I can't understand what is wrong can smn help?
Im using CLion, Cmake looks like this:
cmake_minimum_required(VERSION 3.21)
project(untitled1)
set(CMAKE_CXX_STANDARD 14)
add_executable(untitled1 main.cpp)
Here is full version of code:
#include <chrono>
#include <iostream>
#include <vector>
#include <set>
#include <random>
#include <algorithm>
time_t start, end;
const int tl = 20;
void check(std::vector<bool>& color, const std::string& paint, int n) {
if (paint[n] == 'R') {
color[0] = false;
} else if (paint[n] == 'G') {
color[1] = false;
} else {
color[2] = false;
}
}
std::string available_color(std::vector<bool>& color) {
std::string s;
if (color[0]) {
s += 'R';
}
if (color[1]) {
s += 'G';
}
if (color[2]) {
s += 'B';
}
return s;
}
std::string TryPaint(std::vector<std::set<int>>& edges, std::string paint, bool& success, int v) {
std::vector<bool> was(v + 1);
int count = 0;
std::vector<int> deck;
for (int i = 0; i < v; ++i) {
deck.push_back(i + 1);
}
std::random_shuffle(deck.begin(), deck.end());
while (count != v) {
auto now = deck[count];
std::vector<bool> color = {true, true, true};
check(color, paint, now);
// std::cout << now << '\n';
for (const auto& i : edges[now]) {
std::time(&end);
if (end - start >= tl) {
success = false;
return "";
}
if (was[i]) {
check(color, paint, i);
}
}
std::string choice = available_color(color);
// std::cout << choice << '\n';
if (choice.empty()) {
success = false;
return "";
} else {
++count;
was[now] = true;
char new_color = choice[0];
paint[now] = new_color;
}
}
success = true;
return paint;
}
int main(){
std::time(&start);
std::time(&end);
int v, e;
std::cin >> v >> e;
std::string paint;
std::cin >> paint;
paint = '#' + paint;
std::vector<std::set<int>> edges(v + 1);
for (int i = 0; i < e; ++i) {
int a, b;
std::cin >> a >> b;
edges[a].insert(b);
edges[b].insert(a);
}
std::string new_paint;
bool success = false;
while (!success && end - start < tl) {
std::time(&end);
new_paint = TryPaint(edges, paint, success, v);
// std::cout << "-------------------------------------------------\n";
}
if (success) {
for (int i = 1; i < new_paint.size(); ++i) {
std::cout << new_paint[i];
}
} else {
std::cout << "Impossible";
}
std::cout << '\n';
return 0;
}
Use difftime() to calculate the number of seconds between two time_t variables. The time_t is opaque and can contain different values on different systems according to the doc.
Given a string with repeating characters and a burst length, output the string such that the count of the same adjacent characters in the string is less than the burst length.
Input : abbccccdd, burstLen = 3
Correct Output : abbdd
My Output: abbd
Input : abbcccdeaffff, burstLen = 3
Correct Output: abbdea
My Output: abbea
//Radhe krishna ki jytoi alokik
#include <bits/stdc++.h>
using namespace std;
string solve(string s, int burstLen)
{
stack<pair<char, int>> ms;
for (int i = 0; i < s.size(); i++)
{
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
else
{
if(ms.empty() == true || ms.top().first != s[i])
{
if(!ms.empty() && ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
//(UPDATE)
ms.push({s[i], 1});
}
else
ms.push({s[i], 1});
}
}
}
if(!ms.empty() and ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
}
string ans = "";
while (!ms.empty())
{
ans += ms.top().first;
ms.pop();
}
reverse(ans.begin(), ans.end());
return ans;
}
int main()
{
string s;
int burstLen;
cin >> s;
cin >> burstLen;
cout << solve(s, burstLen) << "\n";
}
It would be better at least to use the container adapter std::queue instead of std::stack because there would not be a need to call the algorithm std::reverse.
Moreover if items of the stack contain the second data member that stores frequencies then you could just increase this data member for repeated characters instead of placing each repeated character in the stack.
For example this code snippet in your program
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
makes the function definition too complicated and unclear because the same character is pushed on the stack with different frequencies.
Nevertheless if you want to use the container adapter std::stack the function definition could look simpler. You are not using features of the class std::string.
Here is a demonstrative program that shows how the function could be written using your approach with std::stack.
#include <iostream>
#include <string>
#include <utility>
#include <stack>
#include <iterator>
#include <algorithm>
std::string solve( const std::string &s, size_t burstLen )
{
std::stack<std::pair<char, size_t>> stack;
for ( const auto &c : s )
{
if ( stack.empty() || stack.top().first != c )
{
stack.push( { c, 1 } );
}
else
{
++stack.top().second;
}
}
std::string ans;
while ( !stack.empty() )
{
if ( stack.top().second < burstLen )
{
ans.append( stack.top().second, stack.top().first );
}
stack.pop();
}
std::reverse( std::begin( ans ), std::end( ans ) );
return ans;
}
int main()
{
std::cout << solve( "abbccccdd", 3 ) << '\n';
std::cout << solve( "abbcccdeaffff", 3 ) << '\n';
}
The program output is
abbdd
abbdea
It is interesting to use the stack when after removing a sequence of characters that is not less than the burst length you get from the left and right side sub-sequences anew sequence that again is not less than burst length and you need also to remove it.
In this case you can use two stacks.
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <utility>
#include <stack>
#include <iterator>
#include <algorithm>
std::string solve( const std::string &s, size_t burstLen )
{
std::stack<std::pair<char, size_t>> stack_in;
for ( const auto &c : s )
{
if ( stack_in.empty() || stack_in.top().first != c )
{
stack_in.push( { c, 1 } );
}
else
{
++stack_in.top().second;
}
}
std::stack<std::pair<char, size_t>> stack_out;
while ( !stack_in.empty() )
{
if ( !stack_out.empty() && stack_out.top().first == stack_in.top().first )
{
if ( stack_out.top().second + stack_in.top().second < burstLen )
{
stack_out.top().second += stack_in.top().second;
}
else
{
stack_out.pop();
}
}
else if ( stack_in.top().second < burstLen )
{
stack_out.push( stack_in.top() );
}
stack_in.pop();
}
std::string ans;
while ( !stack_out.empty() )
{
ans.append( stack_out.top().second, stack_out.top().first );
stack_out.pop();
}
return ans;
}
int main()
{
std::cout << solve( "abbccccdd", 3 ) << '\n';
std::cout << solve( "abbcccdeaffff", 3 ) << '\n';
std::cout << solve( "aabcddeeedccbaa", 3 );
}
The program output is
abbdd
abbdea
aabbaa
I gave it a try but it looks complicated so I suggest making a simpler function using a few functions from the standard library.
Example:
#include <algorithm>
#include <iostream>
#include <initializer_list>
#include <iterator>
std::string solve(const std::string& in, size_t burstlen) {
std::string retval;
for(std::string::const_iterator begin = in.cbegin(), bend;
begin != in.end();
begin = bend)
{
// find the first char not equal to the current char
bend = std::find_if_not(std::next(begin), in.end(),
[curr=*begin](char ch){ return ch==curr; });
if(std::distance(begin, bend) < burstlen) {
// length ok, append it
retval.append(begin, bend);
}
}
return retval;
}
int main() {
std::initializer_list<std::string> tests{
"abbccccdd", "abbcccdeaffff"};
for(auto test : tests) std::cout << solve(test, 3) << '\n';
}
Output:
abbdd
abbdea
My Approach to the Solution :
Create a Stack of pair which consists of character and character count
If the Stack is empty or the top element of the stack is not equal to the current element in the string
Case 1: if the frequency of the top element of the stack is greater than or equal to k, store it in a variable say count, Pop the element of Stack count times.
Case 2: if the Stack is Empty, then simply push the element in stack with frequency 1.
Upon Traversing the complete string, if the top element of the stack is having a frequency greater than bursten, start removing elements from the stack (count) number of times.
Now, we have leftout elements in the stack, Start popping them and store them in a string and reverse the string to preserve the order.
Return the new string.
UPDATE : SOLVED. Missing one line in this condition if(ms.empty() == true || ms.top().first != s[i]) After popping the elements, We also have to insert the present element with character frequency 1.
#include<iostream>
#include<stack>
using namespace std;
string solve(string s, int burstLen)
{
stack<pair<char, int>> ms;
for (int i = 0; i < s.size(); i++)
{
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
else
{
if(ms.empty() == true || ms.top().first != s[i])
{
if(!ms.empty() && ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
ms.push({s[i], 1});
}
else
ms.push({s[i], 1});
}
}
}
if(!ms.empty() and ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
}
string ans = "";
while (!ms.empty())
{
ans += ms.top().first;
ms.pop();
}
reverse(ans.begin(), ans.end());
return ans;
}
int main()
{
int t;
cin >> t;
while(t--)
{
string s;
int burstLen;
cin >> s >>burstLen;
cout << solve(s, burstLen) << "\n";
}
}
private void solve(){
System.out.printf("%s\n", solve("abbccccdd", 3));
System.out.printf("%s\n", solve("abbcccdeaffff", 3));
}
private LinkedList<Node> addToQueue(String S){
int N = S.length();
LinkedList<Node> queue = new LinkedList<>();
queue.addFirst(new Node(S.charAt(0), 1));
for(int i=1;i<N;i++){
if(!queue.isEmpty() && queue.getFirst().val==S.charAt(i)) {
queue.getFirst().count +=1;
} else {
queue.addFirst(new Node(S.charAt(i), 1));
}
}
return queue;
}
private String solve(String S, int K){
if(S==null || S.length()==0) return "";
int N = S.length();
LinkedList<Node> queue = addToQueue(S);
StringBuilder buf = new StringBuilder();
while(!queue.isEmpty()) {
Node node = queue.removeLast();
int count = node.count;
if(count>=K) continue;
if(isSame(queue, buf)){
while(isSame(queue, buf)) {
count += queue.getLast().count;
queue.removeLast();
}
if(count>=K) buf.deleteCharAt(buf.length()-1);
else {
while(count-->0){
buf.append(node.val);
}
}
} else {
if(count>=K) continue;
while(count-->0){
buf.append(node.val);
}
}
}
return buf.toString();
}
private boolean isSame(LinkedList<Node> queue, StringBuilder buf){
if(queue.isEmpty() || buf.length()==0) return false;
return queue.getLast().val == buf.charAt(buf.length()-1);
}
class Node {
char val;
int count;
public Node(char c, int count){
this.val = c;
this.count = count;
}
}
So I'm trying to create this priority queue to handle my "Order" objects, I'm running into a problem where an object containing the same key/priority will be placed at an early earlier position than others initialized first. I have provided the expected and received output alongside the 83 lines of code of how I constructed my heap with notes
#include <iostream>
#include <vector>
struct Order {
int value = -1;
int priority = -1;
bool operator <(Order const& RHS) { return priority < RHS.priority; }
};
class heap {
private:
std::vector<Order> orders{ Order{} };
int size{}; //initalizes it at 0
int p(int index) { return index >> 1; }
int l(int index) { return index << 1; }
int r(int index) { return (index << 1) + 1; }
public:
bool isEmpty() const { return size == 0; }
void shiftUp(int position);
void shiftDown(int position);
void add(Order new_entry);
Order removeTop();
Order& getTop() { return orders[1]; }
};
template <typename T>
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
heap h;
h.add(Order{1,3}); h.add(Order{2,2});
h.add(Order{3,3}); h.add(Order{5,1});
h.add(Order{6,2}); h.add(Order{7,2});
h.add(Order{8,3}); h.add(Order{9,1});
h.add(Order{23,3});
std::cout << "value" << " key(priority)" << "\n";
for (int i = 0; i < 8; i++) {
Order temp = h.removeTop();
std::cout << temp.value << "\t " << temp.priority << "\n";
}
}
void heap::shiftUp(int position) {
if (position > size) return;
if (position == 1) return;
if (orders[p(position)] < orders[position]) {
mySwap(orders[position], orders[p(position)]);
shiftUp(p(position));
}
}
void heap::shiftDown(int position) {
if (position > size) return;
int greaterPosition = position;
if (l(position) <= size && orders[position] < orders[l(position)])
greaterPosition = l(position);
if (r(position) <= size && orders[greaterPosition] < orders[r(position)])
greaterPosition = r(position);
if (greaterPosition != position) {
mySwap(orders[position], orders[greaterPosition]);
shiftDown(greaterPosition);
}
}
void heap::add(Order new_entry) {
if (size + 1 >= orders.size()) orders.push_back(Order{});
orders[++size] = new_entry;
shiftUp(size);
}
Order heap::removeTop() {
Order temp = orders[1];
mySwap(orders[1],orders[orders.size() - 1]); size--;
orders.pop_back();
shiftDown(1);
return temp;
}
/*
Expected Output
Value key(priority)
1 3
3 3
8 3
23 3
2 2
6 2
7 2
5 1
9 1
Recieved/wrong Output
value key(priority)
1 3
23 3
3 3
8 3
2 2
6 2
7 2
5 1
*/
Fixed code from answered information above
#include <iostream>
#include <vector>
struct Order {
int value = -1;
int priority = -1;
int FIFO;
bool operator <(Order const& RHS) {
if (priority == RHS.priority)
return FIFO > RHS.FIFO;
else
return priority < RHS.priority;
} //compares keys for larger presidence
};
class heap {
private:
std::vector<Order> orders{ Order{} };
int size{}; //initalizes it at 0
int p(int index) { return index >> 1; }
int l(int index) { return index << 1; }
int r(int index) { return (index << 1) + 1; }
public:
bool isEmpty() const { return size == 0; }
void shiftUp(int position);
void shiftDown(int position);
void add(Order new_entry);
Order removeTop();
Order& getTop() { return orders[1]; }
};
template <typename T>
void mySwap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
int main() {
heap h;
h.add(Order{1,3}); h.add(Order{2,2});
h.add(Order{3,3}); h.add(Order{5,1});
h.add(Order{6,2}); h.add(Order{7,2});
h.add(Order{8,3}); h.add(Order{9,1});
h.add(Order{23,3});
std::cout << "value" << " key(priority)" << "\n";
for (int i = 0; i < 8; i++) {
Order temp = h.removeTop();
std::cout << temp.value << "\t " << temp.priority << "\n";
}
}
void heap::shiftUp(int position) {
if (position > size) return;
if (position == 1) return;
if (orders[p(position)] < orders[position]) {
mySwap(orders[position], orders[p(position)]);
shiftUp(p(position));
}
}
void heap::shiftDown(int position) {
if (position > size) return;
int greaterPosition = position;
if (l(position) <= size && orders[position] < orders[l(position)])
greaterPosition = l(position);
if (r(position) <= size && orders[greaterPosition] < orders[r(position)])
greaterPosition = r(position);
if (greaterPosition != position) {
mySwap(orders[position], orders[greaterPosition]);
shiftDown(greaterPosition);
}
}
void heap::add(Order new_entry) {
if (size + 1 >= orders.size()) orders.push_back(Order{});
new_entry.FIFO = size + 1;
orders[++size] = new_entry;
shiftUp(size);
}
Order heap::removeTop() {
Order temp = orders[1];
mySwap(orders[1],orders[orders.size() - 1]); size--;
orders.pop_back();
shiftDown(1);
return temp;
}
In general, heap does not have FIFO property until you implement something that helps doing so. In your order class, you are only comparing using the priority value. In your Order class, you are comparing two Orders by only their priority value. You need a additional variable that serves as the purpose for recording the timing when that value was inserted, and compare according to that.
If you are using the variable value for that purpose, you need to specify in your overloaded < method, what do you want to do when two Order's priority values are equal. Currently, you are only using the priority variable to compare. You are not specifying what do you want to do when the priority of two Orders are equal. You have to specify what do you want to do when the priority value of two variables are equal. Maybe compare a timing variable.
I have a template class that I am testing:
class SparseMat {
private:
FHvector<FHlist<MatNode<Object>>> matrix;
int numOfRows, numOfCols;
const Object defaultValue;
public:
SparseMat(int r, int c, const Object& defaultVal);
const Object & get(int r, int c) const;
bool set(int r, int c, const Object& x);
};
template <class Object>
SparseMat<Object>::SparseMat(int r, int c, const Object& defaultVal) : defaultValue(defaultVal) {
numOfRows = r;
numOfCols = c;
matrix.resize(numOfRows);
for (int counter = 0; counter < numOfRows; counter++) {
FHlist<MatNode<Object>> currentRow;
matrix.push_back(currentRow);
}
}
template <class Object>
bool SparseMat<Object>::set(int r, int c, const Object& x) {
if (r >= numOfRows || r < 0 || c < 0 || c >= numOfCols) {
return false;
}
if (r == 9 && c == 9) {
cout << x << endl;
}
if (r == 9 && c == 9) {
cout << x << endl;
}
for (FHlist<MatNode<Object>>::iterator iter = matrix[r].begin(); iter != matrix[r].end(); ++iter) {
if ((*iter).getCol() == c) {
if (x == defaultValue) {
matrix[r].erase(iter);
return true;
}
else {
(*iter).data = x;
return true;
}
}
}
matrix[r].push_back(MatNode<Object>(c, x));
return true;
}
template <class Object>
const Object & SparseMat<Object>::get(int r, int c) const {
if (r >= numOfRows || r < 0 || c < 0 || c >= numOfCols) {
throw OutOfBoundsException();
}
FHlist<MatNode<Object>> wantedRow = matrix[r];
for (FHlist<MatNode<Object>>::iterator iter = wantedRow.begin(); iter != wantedRow.end(); ++iter) {
if ((*iter).getCol() == c) {
return (*iter).getData();
}
}
return NULL;
}
MatNode is as follows:
template <class Object>
class MatNode
{
protected:
int col;
public:
Object data;
MatNode(int cl = 0, Object dt = Object()) : col(cl), data(dt) { }
int getCol() const { return col; }
const Object & getData() const {return data; }
};
The immensely strange thing is my two outputs print two different things. The first prints 21, as expected. The second prints out some random float, which is definitely not expected as I have changed nothing with x between the two outputs.
#include <iostream>
using namespace std;
#include "FHsparseMat.h"
#define MAT_SIZE 100000
typedef SparseMat<float> SpMat;
int main()
{
SpMat mat(MAT_SIZE, MAT_SIZE, 0);
mat.set(3, 9, 21);
cout << mat.get(3, 9) << endl;
mat.set(9, 9, 21);
cout << mat.get(9, 9) << endl;
mat.set(9, 9, mat.get(3,9));
cout << mat.get(9, 9) << endl;
}
Here is my tester. If I replace mat.get(3,9) with the hard coded value of 21, the issue disappears, if that helps.
get() has a return type of const Object &.
As a result, the final line of the function
return 0; // source code says NULL but preprocessor replaces that with 0
is returning a dangling reference to a temporary Object implicitly constructed with the value 0.
Using that dangling reference will, of course, cause undefined behavior.
It's not completely clear why that line is reached, but the logic that erases an item if you write the same value to the same location certainly seems suspicious. IMO you should only remove an item when the value written is zero.
The issue is that Object MatNode::getData() const is not returning a reference, and you are returning a reference in const Object & SparseMat<Object>::get(int r, int c) const. Change it to:
Object SparseMat<Object>::get(int r, int c) const.
I have a class with a method that should return a vector of strings. the getCommVector method has to push_back the elements of a string array into a string vector that can then be returned by the method. When trying to add a string element to the string vector i get:
libc++abi.dylib: terminate called throwing an exception
2Program ended with exit code: 0
I cannot understand why I can't push_back strings to the vector. Any ideas?
Thanks in advance!
code segments of interest (edited after suggestions):
class Command {
public:
//Command (std::string, bool, bool);
void setOperators(std::string,bool, bool);
void analyseCommand();
Command();
std::vector<std::string> getCommVector ();
private:
int numOperators; //number of total commands
int opCount; //current command number
std::string input_string;
bool field_command, byte_command;
std::string commVector[3];
std::vector<std::string> finalCommVector;
void byte_analysis();
void field_analysis();
void decode_command();
void syntax_error();
void decode_error();
};
Command::Command() : numOperators(0), opCount(0), field_command(false),byte_command(false)
{
}
std::vector<std::string> Command::getCommVector ()
{
std::string s ="test";
finalCommVector.push_back("s");
return finalCommVector;
}
adding SSCE:
class Command {
public:
//Command (std::string, bool, bool);
void setOperators(std::string,bool, bool);
void analyseCommand();
Command();
std::vector<std::string> getCommVector ();
private:
int numOperators; //number of total commands
int opCount; //current command number
std::string input_string;
bool field_command, byte_command;
std::string commVector[3];
std::vector<std::string> finalCommVector;
void byte_analysis();
void field_analysis();
void decode_command();
void syntax_error();
void decode_error();
};
Command::Command() : numOperators(0), opCount(0), field_command(false),byte_command(false)
{
}
void Command::syntax_error()
{
std::cout<<"Incorrect Syntax Error: Usage: linuxcut -b num -f num \n";
exit(EXIT_FAILURE);
}
void Command::decode_error()
{
std::cout<<"Decode Error: Usage: linuxcut -b num -f num \n";
exit(EXIT_FAILURE);
}
void Command::analyseCommand()
{
if (byte_command) {
//start byte command analysys
byte_analysis();
}
else if (field_command)
{
//start field command analysys
field_analysis();
}
}
void Command::setOperators(std::string input_argument, bool is_field, bool is_byte)
{
input_string = input_argument;
field_command = is_field;
byte_command = is_byte;
}
std::vector<std::string> Command::getCommVector ()
{
std::string s = "ssd";
finalCommVector.push_back(s);
/*
for (int i = 0; i<sizeof(commVector); i++)
{
if (commVector[i] != "")
{
//debug
std::cout<<"asdas";
}
}
*/
return finalCommVector;
}
void Command::byte_analysis()
{
int next_state = 0;
int dashCount = 0;
int commVectIndex = 0;
//iterate through string and check if the argument is valid
for (int i= 0; i<input_string.length(); i++) {
switch (next_state) {
case 0: //start
//if character is a number:
if (isdigit(input_string.at(i)))
{
//first elemnt of command commVector is number
commVector[commVectIndex]+=input_string.at(i);
//DEBUG
std::cout<<commVector[commVectIndex];
next_state = 1;
}
//if character is a dash:
else if (input_string[i] == '-')
{
//increment dashCount
dashCount++;
//if next character in input_string is a number continue
if (isdigit(input_string[i+1])) {
commVector[commVectIndex]+=input_string.at(i);
commVectIndex++;
next_state = 1;
}
else //else error
{
syntax_error();
}
}
//if it's niether: error!
else
{
syntax_error();
}
break;
case 1:
//if next character is a number:
if (isdigit(input_string[i]))
{
commVector[commVectIndex]+=input_string.at(i);
next_state = 1;
}
//if next character is dash
else if (input_string[i] == '-'&& dashCount <= 3)
{
dashCount++;
//increment commandVectIndex
commVectIndex++;
next_state = 2;
commVector[commVectIndex]+=input_string.at(i);
//increment commandVectIndex to accomodate next operation
commVectIndex++;
}
//if it's niether: error!
else
{
syntax_error();
}
break;
case 2://previous character was dash
//if next character is number
if (isdigit(input_string[i]))
{
commVector[commVectIndex]+=input_string.at(i);
next_state = 1;
}
//if it's niether: error!
else
{
syntax_error();
}
break;
default:
syntax_error();
break;
}
}
}
void Command::field_analysis()
{
}
/*****************FUNCTIONS DEFINITIONS***************/
void print_usage() {
std::cout<<"Incorrect Syntax Error: Usage: linuxcut -b num -f num \n";
}
/*****************END OF FUNCTIONS DEFINITIONS***************/
/***************** MAIN ***************/
int main(int argc, char *argv[]) {
int opt= 0;
std::string byte = "-1-2,2",field = "";
std::string sub_arg_delimiter = ","; //delimiter for comma serparated arguments
static bool complement = false;
int diffOpt = 0; //stores the difference between optind and argc to read filenames in command
std::string fileName;
//Specifying the expected options
//The two options l and b expect numbers as argument
static struct option long_options[] = {
{"byte", required_argument, 0, 'b' },
{"field", required_argument, 0, 'f' },
{"complement", no_argument, 0, 0 },
{0, 0, 0, 0 }
};
Command testCommand;
testCommand.setOperators("-2-", false, true);
std::vector<std::string> trial = testCommand.getCommVector();
std::cout<<"filename:"<<fileName<<std::endl;
std::cout<<"Selected flags:\n"<< "b: "<< byte<<"\nf: "<<field<<"\ncomplement: "<<complement<<std::endl;
return 0;
}
You're iterating way beyond the array size. sizeof(commVector) returns the size of the array in bytes.
If you have C++11 available, you can do this:
for (const auto &s : commVector) {
if (s != "") {
// as before
}
}
Or at least this (if you only have partial C++11 support):
for (auto it = std::begin(commVector); it != std::end(commVector); ++it) {
std::string s = *it;
// the rest as before
}
Without C++11, you can at least do this:
for (int i = 0; i < sizeof(commVector) / sizeof(commVector[0]); ++i) {
// the rest as before
}
Or provide your own function for obtaining the correct array size:
template <class T, size_t N>
size_t arraySize(const T (&)[N]) { return N; }
// Use:
for (size_t i = 0; i < arraySize(commVector); ++i) {
// the rest as before
}
i<sizeof(commVector);
should be
i<countof(commVector);
if countof/_countof is defined for your compiler. If not, you can do it yourself, it is typically defined as:
#define countof(a) (sizeof(a)/sizeof(a[0]))
and I won't go into discussion about using macros in C++ :)
Of course, you could also use a constant are your array has fixed number of elements, but I guess it's just an example.
sizeof returns the size of the object (in this case the string array) itself, not the count of elements inside the vector.
Because of this, it is equal to number of the array elements multiplied by size of a single string instance, so you try to access non-existing items with operator[].
This is also broken:
finalCommVector.push_back("s");
and probably you meant:
finalCommVector.push_back(s);
If all you need is the array of std::string commVector as a std::vector<String>, you can use std::vecor::assign:
finalCommVector.assign(commVector, commVector+3)
The '3' is the length of you array.