While Loop Error - c++

I have an assignment to merge two sorted vectors into a third sorted vector. I'm sure the solution to this problem is pretty simple, but my brain is fried at the moment and could use your help.
Basically vectors A and B have a size of 3. They will hold integers such as 1, 2, 3 and 4, 5, 6 respectively. I can't seem to get the syntax of my while loop correctly. I've tried making it a do/while loop, putting parentheses around the cases, and a few other things. It just doesn't seem to be reading the part after the &&.
The first for loop just makes the R vector have the right size. And the second for loop just displays the values of the R vector. The result should print out from 1-6, but I'm only seeing 1-3.
Any help would be appreciated!
void::combine(vector<int> A, vector<int> B, vector<int> R) {
int ia = 0, ib = 0, ir = 0;
for (int i = 0; i < A.size() + B.size(); i++) {
R.push_back(0);
}
while (ia != A.size() && ib != B.size()) {
if (A[ia] < B[ib]) {
R[ir] = A[ia];
ia += 1;
}
else {
R[ir] = B[ib];
ib += 1;
}
ir += 1;
}
for (int i = 0; i < R.size(); i++) {
cout << "L3[" << i << "] = " << R[i] << endl;
}
}

Assuming A contains [1,2,3] and B contains [4,5,6] as you say, this will not add any of the element in the B vector to the R vector.
This is because on the 4th iteration, ia == 3, and so the conjunctive condition is no longer true..
Try changing it to while(ia != A.size() || ib != B.size())

Probably you should avoid the loop altogether:
void combine(vector<int> const& A, vector<int> const& B, vector<int> & R) {
R.resize( A.size() + B.size() );
std::copy( A.begin(), A.end(), R.begin() );
std::copy( B.begin(), B.end(), R.begin()+A.size() );
std::sort( R.begin(), R.end() );
for ( int i = 0; i < R.size(); ++i )
{
cout << "L3[" << i << "] = " << R[i] << endl;
}
}
This is suboptimal as you are first copying and then ordering, but for a small size it will have no impact.
On the actual issues with your code: try to avoid pass-by-value, use resize instead of multiple push_back() to fix the size (note that if the R argument to your function was a non-empty vector then the final size would be bigger than you want). Consider using a return value instead of a reference argument --easier to read. You looped until the first of the counters reached the end, but left the rest of the elements in the other container without copying.
A manual implementation, using iterators would also be simpler:
typedef std::vector<int> vector_t;
vector_t combine( vector_t const & a, vector_t const & b ) {
vector_t r( a.size() + b.size() ); // [*]
vector_t::const_iterator ita = a.begin(), enda = a.end();
vector_t::const_iterator itb = b.begin(), endb = b.end();
vector_t::iterator itr = r.begin();
while ( ita != enda && itb != endb ) {
if ( *ita < *itb )
*itr++ = *ita++;
else
*itr++ = *itb++;
}
if ( ita != enda )
std::copy( ita, enda, itr );
else
std::copy( itb, endb, itr );
return r;
}

I don't know what you're trying to do in the while loop. But if you're just populating the vector R with the elements in A and B, without giving any regard to the order how they're added, then you can use insert function, as:
void::combine(const vector<int> &A, const vector<int> &B, vector<int>& R)
{
R.insert(R.end(), A.begin(), A.end());
R.insert(R.end(), B.begin(), B.end());
}
And if you want to order the vector R, then you can add the following line to the above function:
sort( R.begin(), R.end()); //sorts in increasing order.
You've to #include<algorithm> if you do so. If you want to sort in decreasing order then do this:
bool compare( int a, int b ) { return a > b; }
sort( R.begin(), R.end(), compare); //sorts in decreasing order.

First of all, this smells like a classic merge sort or a piece of it:
http://en.wikipedia.org/wiki/Merge_sort
The objective is to examine elements of the first vector, A, to elements of vector B, and append the elements to a resulting vector R, in order.
Thus if A[i] < B[j], append A[i] to R. With std::vector, there is no need to load the result vector with zeros before starting. See std::vector::push_back().
The following is untested code:
void Sort_Vector(const std::vector& A, const std::vector& B, std::vector& result)
{
unsigned int index_a = 0; // Point to first element in first vector.
unsigned int index_b = 0; // Point to first element in second vector.
result.clear(); // Clear all elements, so size == 0.
while ((index_a < A.size()) && (index_b < B.size())
{
if (A[index_a] < B[index_b])
{
result.push_back(A[index_a]);
++index_a;
}
else // B[index_b] <= A[index_a]
{
result.push_back(B[index_b]);
++index;
}
}
// Append any remaining elements to the result vector.
// Only one of the two loops should be executed,
// the other will fail the comparison expression
// and not execute.
for (; index_a < A.size(); ++index_a)
{
result.push_back(A[index_a]);
}
for (; index_b < B.size(); ++index_b)
{
result.push_back(B[index_b]);
}
return;
}
Notice the difference between my function's signature (parameters) and yours. I'm passing the source vectors as constant data and the result vector is passed by reference which enables my function to modify the caller's result vector.
Also, I'm lazy and using the std::vector::push_back() method. I believe this is more readable than assigning to an element in the result vector. The push_back method implies that I am appending to the vector. The assignment route may catch readers off-guard if they forget that a vector will expand in order resolve the assignment.

that's because of your && condition. as soon as ia == A.size(), the first part of the condition (ia != A.size()) will always evaluate to false and the ib part of your loop won't execute.
to fix it, you can change the condition to : (iA < A.size()) || (iB < B.size())

e.g. with 123 and 456 what is being done right now.
Initialize R to {0,0,0,0,0,0}
until all values from one vector are inserted into R compare candidates and insert smaller one into R, get next candidate from winner list.
and that's all - I don't know that is the purpose of the function if you'll write it I/We can provide solution otherwise just review 2nd point in above form.

The syntax is fine (the code wouldn't compile otherwise), but your loop condition isn't. Given your example A = { 1, 2, 3 } and B = { 4, 5, 6 }, the loop will enter the A[ia] < B[ib] branch three times and increment ia to 3. Once this happens, the first part of the loop condition, ia != A.size() won't be true, and so the loop ends.
Since you already know how many items you need to place in the result vector, I'd recommend replacing your while loop with a simple for one with the same body.

Related

Most efficient way to find iterators of 4 maximum values in const vector in C++

I have to find 4 the biggest numbers in a const vector and return their positions. I want this code to have the best time and space complexity. My first idea is to copy this const vector into vector and bubble sort it 4 times. That gives me 4*N but i have to create a vector. Second idea is to put everything from this const vector into priority_queue. That gives me a N*log2(N) time complexity without creating another variables. The maximum of N is around 100.
Is there any other options to do it in the fastest and the least space-consuming way?
EDIT: It doesn't matter which one is the biggest, I just need to return position of this 4 items in the input vector.
O(n) solution
std::vector<int>::iterator max1 = v.begin(), max2 = v.begin(), max3 = v.begin(), max4 = v.begin();
for(std::vector<int>::iterator it = v.begin(); it != v.end(); it++) {
if((*max1) < (*it)) {
max4 = max3;
max3 = max2;
max2 = max1;
max1 = it;
} else if((*max2) < (*it)) {
max4 = max3;
max3 = max2;
max2 = it;
} else if((*max3) < (*it)) {
max4 = max3;
max3 = it;
} else if((*max4) < (*it)) {
max4 = it;
}
}
You can implement this quite easily with an extra vector, and the nth_element algorithm, which is O(n) time:
std::vector<int> const v = ...;
// create a vector of elements with original indexes
std::vector<std::pair<int,int>> res;
// populate the result vector
int k = 0;
for (int i : v)
res.push_back({i,k++});
// find the maximum 4 elements
std::nth_element(res.begin(), res.begin() + 4, res.end(),
[](auto const &a, auto const &b) { return a.first > b.first; });
Here's a demo.
Note that this solution uses O(n) extra space. If N grows large, then this might not be the right approach for finding just 4 largest elements. It's still a good approach if you want the M largest elements, where M grows like N.
Yes, use a heap of size four. Then you iterate through the vector and update the heap accordingly.
Sample code using std heap methods and finding minimum values (from here) follows.
const std::vector<int> input;
const size_t n = 4;
std::vector<int> ret(n);
auto dfirst = ret.begin(), dlast = ret.end();
// initialize heap with infinity distances
std::fill(dfirst, dlast, 100000000000); // do better here
for (auto it = input.begin(); it != input.end(); ++it)
{
if (*it < *dfirst) {
// remove max. value in heap
std::pop_heap(dfirst, dlast); // add comparator as third arg
// max element is now on position "back" and should be popped
// instead we overwrite it directly with the new element
*(dlast-1) = *it;
std::push_heap(dfirst, dlast); // add comparator as third arg
}
}
std::sort_heap(dfirst, dlast); // remove if not needed, or add comparator as third arg
return ret;
Adapt accordingly:
Use a pair of index, value in the heap to keep track of positions which you like to return
Use comparator that compares on value in the pair and establishes a desc. ordering
This is more generic than #Jugal Rawlani's solution if your number n might change/grow in the future. Otherwise his idea wins.
read the 4 first elements into a vector of 4. sort this vector so that minimum of the 4 is in index 0.
loop on remaining items of the const vector, if current value > min, replace it and re-sort the 4 element vector

Return an array which contains number of elements in an array that is lesser or equal to elements in a given array

I came across this problem and wondering if there could be a better complexity to solve the problem.
For e.g.
array a = [1,4,2,4]
array b = [3,5]
DESIRED OUTPUT ==> [2, 4]
EDIT: Put another example
array a = [1,4,2,4]
array b = [3, 1000000]
DESIRED OUTPUT ==> [2,4]
So far, what I've found and tried runs in O(nlogn) + O(blogn) and O(n).
O(nlogn) + O(blogn) approach:
int binarysearch(vector<int>arr, int l, int r, int target)
{
int mid;
while(l <= r)
{
mid = (r+l) / 2;
if(arr[mid] > target)
r = mid - 1;
else
l = mid + 1;
}
return r;
}
vector<int> counts(vector<int> a, vector<int> b)
{
vector<int> result;
sort(a.begin(), a.end()); // O(nlogn)
for(auto i : b){
int count = binarysearch(a, 0, a.size()-1, b); // b*O(log n) times
result.push_back(count)
}
return result;
}
O(n) approach:
vector<int> counts(vector<int> a, vector<int> b)
{
vector<int> result;
int maxi = *max_element(b.begin(), b.end()) + 1;
int mymap[maxi] = {0};
for(auto i : a) mymap[i]++;
for(int i = 1; i < maxi; i++){
mymap[i] = mymap[i] + mymap[i-1];
}
for(auto i : b){
result.push_back(mymap[i]);
}
return result;
}
[I am] wondering if there could be a better complexity to solve the problem.
Time complexity.
O(n) approach:
No, there exists no solution with less than linear time complexity.
That said, you linear solution is incorrect. If the input array contains the value 1000000 or greater, or a negative number, then you access outside the bounds of mymap and behaviour is undefined. Furthermore, i <= 1000000 also accesses mymap outside the bound upon the last iteration. Besides, int[1000000] is way too big to be a local variable. On some systems, even one such variable could cause the stack to overflow.
There is no better way doing this than O(n).
So this is also O(n) but with STL style adapted:
template <class Iter1, class Iter2>
std::vector<std::size_t> counts(const Iter1 beg_a, const Iter1 end_a, const Iter2 beg_b, const Iter2 end_b)
{
std::vector<std::size_t> result;
const auto& max = *std::max_element(beg_b, end_b);
std::vector<std::size_t> mymap(max + 1, 0);
for (auto iter = beg_a; iter != end_a; iter++)
{
if (*iter <= max)
{
mymap[*iter]++;
}
}
for (std::size_t i = 1; i < mymap.size(); i++)
{
mymap[i] = mymap[i] + mymap[i - 1];
}
for (auto iter = beg_b; iter != end_b; iter++)
{
result.push_back(mymap[*iter]);
}
return result;
}
Okay, it turns out there's a faster way to compute the map index. For e.g. given a = {1,4,2,4,5,8,80} and b = {3,1000000}. DESIRED OUTPUT would be [2,7].
Using my previous approach, I would need to compute mymap[4], mymap[5].. mymap[9999]....mymap[1000000]. And that's why the program crashes and returns running time error.
the way we handle this is to use for(auto& entry:mymap) which gives access to all dictionary/map. Then, we use the upper_bound STL C++ to return the correct map.
vector<int> counts(vector<int> nums, vector<int> maxes){
vector<int> result;
map<int,unsigned int> mymap;
for(auto i : nums) mymap[i]++;
// doesn't need to run 1000000 times
int temp = 0;
for(auto& entry: mymap){
entry.second = entry.second + temp;
temp = entry.second;
//cout << "first : " << entry.first << "second: " << entry.second << endl;
}
map<int,unsigned int>::iterator itl;
for(auto i : maxes){
itl = --mymap.upper_bound(i); // points to the correct map
result.push_back(itl->second);
}
return result;
}
First let's take better notations: let's call A the number of elements in a, B the number of elements in B, and say elements are M bits values.
Your solution is, as others said, A log(A) to construct the map plus B log(A) to get the returned values.
Using a https://en.wikipedia.org/wiki/Y-fast_trie you could get (A+B) log M instead, which is faster if A >> M (but probably slower in practice for most use cases).

Problems with vectors, how to remove the arrays in my vectors?

I have created a function that creates all the possible solutions for a game that I am creating... Maybe some of you know the bullcow game.
First I created a function that creates a combination of numbers of max four integers and the combination can't have any repeating number in it... like...
'1234' is a solution but not '1223' because the '2' is repeating in the number. In total there is 5040 numbers between '0123' and '9999' that haven't repeating numbers.
Here is my function:
std::vector <std::array<unsigned, 4>> HittaAllaLosningar(){
std::vector <std::array<unsigned, 4>> Losningar;
for (unsigned i = 0; i < 10; i++) {
for (unsigned j = 0; j < 10; j++) {
for (unsigned k = 0; k < 10; k++) {
for (unsigned l = 0; l < 10; l++) {
if (i != j && i != k && i != l && j != k && j != l && k != l) {
Losningar.push_back({i,j,k,l});
}
}
}
}
}
return Losningar;
}
Now let's say I have the number '1234' and that is not the solution I am trying to find, I want to remove the solution '1234' from the array since that isn't a solution... how do I do that? have been trying to find for hours and can't find it. I have tried vector.erase but I get errors about unsigned and stuff... also its worth to mention the guesses are in strings.
What I am trying to do is, to take a string that I get from my program and if it isn't a solution I want to remove it from the vector if it exists in the vector.
Here is the code that creates the guess:
std::string Gissning(){
int random = RandomGen();
int a = 0;
int b = 0;
int c = 0;
int d = 0;
for (unsigned i = random-1; i < random; i++) {
for (unsigned j = 0; j < 4; j++) {
if (j == 0) {
a = v[i][j];
}
if (j == 1) {
b = v[i][j];
}
if (j == 2) {
c = v[i][j];
}
if (j == 3) {
d = v[i][j];
}
}
std::cout << std::endl;
AntalTry++;
}
std::ostringstream test;
test << a << b << c << d;
funka = test.str();
return funka;
}
The randomgen function is just a function so I can get a random number and then I go in the loop so I can take the element of the vector and then I get the integers of the array.
Thank you very much for taking your time to help me, I am very grateful!
You need to find the position of the element to erase.
std::array<unsigned, 4> needle{1, 2, 3, 4};
auto it = std::find(Losningar.begin(), Losningar.end(), needle);
if (it != Losningar.end()) { Losningar.erase(it); }
If you want to remove all the values that match, or you don't like checking against end, you can use std::remove and the two iterator overload of erase. This is known as the "erase-remove" idiom.
std::array<unsigned, 4> needle{1, 2, 3, 4};
Losningar.erase(std::remove(Losningar.begin(), Losningar.end(), needle), Losningar.end());
To erase from a vector you just need to use erase and give it an iterator, like so:
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
auto it = vec.begin(); //Get an iterator to first elements
it++; //Increment iterator, it now points at second element
it = vec.erase(it); // This erases the {4,3,2,1} array
After you erase the element, it is invalid because the element it was pointing to has been deleted. Ti continue to use the iterator you can take the return value from the erase function, a valid iterator to the next element after the one erased, in this the case end iterator.
It is however not very efficient to remove elements in the middle of a vector, due to how it works internally. If it's not important in what order the different solution are stored, a small trick can simplify and make your code faster. Let's say we have this.
std::vector<std::array<unsigned, 4>> vec;
vec.push_back({1,2,3,4});
vec.push_back({4,3,2,1});
vec.push_back({3,2,1,4});
To remove the middle one we then do
vec[1] = vec.back(); // Replace the value we want to delete
// with the value in the last element of the vector.
vec.pop_back(); //Remove the last element
This is quite simple if you have ready other functions:
using TestNumber = std::array<unsigned, 4>;
struct TestResult {
int bulls;
int cows;
}
// function which is used to calculate bulls and cows for given secred and guess
TestResult TestSecretGuess(const TestNumber& secret,
const TestNumber& guess)
{
// do it your self
… … …
return result;
}
void RemoveNotMatchingSolutions(const TestNumber& guess, TestResult result)
{
auto iter =
std::remove_if(possibleSolutions.begin(),
possibleSolutions.end(),
[&guess, result](const TestNumber& possibility)
{
return result == TestSecretGuess(possibility, guess);
});
possibleSolutions.erase(iter, possibleSolutions.end());
}
Disclaimer: it is possible to improve performance (you do not care about order of elements).

Correctly erasing an element from a vector

If I have a table of vectors declared as
vector<int> table[9][9]
and I want to compare and delete the element if it already exists, would the deletion be:
for(int row = 0; row < 9; row++)//erases the current choice from the whole row
{
for(int h = 0; h < (int)table[row][k].size();h++)
{
if(table[row][k][h] == table[i][k][0])
{
table[row][k].erase(table[row][k].begin() + h);
}
}
}
I thought this would work, but I'm not 100% because I tried to delete every element using this technique and it didn't work, for those of you who want to see the code I used to delete all the elements, then it is:
for(int i = 0; i < 9; i++)
for(int k = 0; k < 9; k++)
for(int n = 0; n < table[i][k].size();n++)
table[i][k].erase(table[i][k].begin + n);
this method did not work, so I used clear instead.
I don't know what choice and k are, but to erase all values from a vector v that are equal to a particular value val use the "erase-remove idiom":
v.erase(
std::remove(v.begin(), v.end(), val),
v.end()
);
Hence, to do this same thing for all vectors in table:
for (auto &row : table) {
for (auto &v : row) {
v.erase(
std::remove(v.begin(), v.end(), val),
v.end()
);
}
}
If you have a more complicated condition than equality, use remove_if in place of remove. But in your case, the extra condition involving puzzle doesn't use the loop variable h, so I think you can test that before looking in the vector:
if (puzzle[row][k] == 0) {
// stuff with erase
}
In C++03 you can't use "range-based for loops" for (auto &row : table). So if you don't have C++11, or if you need the index for use in the puzzle test, then stick with for(int i = 0; i < 9; i++).

Problem with Mergesort in C++

vector<int>& mergesort(vector<int> &a) {
if (a.size() == 1) return a;
int middle = a.size() / 2;
vector<int>::const_iterator first = a.begin();
vector<int>::const_iterator mid = a.begin() + (middle - 1);
vector<int>::const_iterator last = a.end();
vector<int> ll(first, mid);
vector<int> rr(mid, last);
vector<int> l = mergesort(ll);
vector<int> r = mergesort(rr);
vector<int> result;
result.reserve(a.size());
int dp = 0, lp = 0, rp = 0;
while (dp < a.size()) {
if (lp == l.size()) {
result[dp] = (r[rp]);
rp++;
} else if (rp == r.size()) {
result[dp] = (l[lp]);
lp++;
} else if (l[lp] < r[rp]) {
result[dp] = (l[lp]);
lp++;
} else {
result[dp] = (r[rp]);
rp++;
}
dp++;
}
a = result;
return a;
}
It compiles correctly but while execution, I am getting:
This application has requested the
runtime to end it in an unusual way.
This is a weird error.
Is there something that is fundamentally wrong with the code?
This result.reserve(a.size()) just affects the vector's capacity, not it's size. (The vector's capacity tells up to which size the vector can grow without needing to re-allocate and copy all members. Basically it's only there for optimization purposes.) You cannot access any members in result after that reservation, since there aren't any. Either use result.push_back(...) instead of result[dp] = ... or result.resize(a.size()) instead of result.reserve(a.size()).
I suppose the former could be more effective.
One problem is with the usage of reserve() (either use resize() or append items with push_back() instead of accessing the index).
if (a.size() == 1) return a;
int middle = a.size() / 2;
vector<int>::const_iterator first = a.begin();
vector<int>::const_iterator mid = a.begin() + (middle - 1);
vector<int>::const_iterator last = a.end();
vector<int> ll(first, mid);
vector<int> rr(mid, last);
This could be another problem. If the size is 2, then ll would end up being an empty vector, and this function doesn't appear to handle this. There doesn't seem to be much reason to subtract 1 from middle anyway.
It is also possible that you are copying things around far more than needed: you shouldn't need the l and r vectors (because they will just be copies of ll and rr), similarly I don't think you need the result vector, since you could just write the merged results right back to a.
reserve() does not change the amount of contents in the vector. You've created an empty vector, reserved a certain size for it, and then used v[i] = x; This is not a valid use of vector since there still isn't any i'th element in the vector.
Use resize() instead.
The error message is very unclear, because it is the standard message of VC++ when an exception goes unhandled. You could add a try-catch-clock to your main to get the exception and a more meaningful error:
int main() {
try {
// do main stuff here
}
catch ( std::exception & e ) {
std::cout << e.what() << std::endl;
}
}
This is for the command-line. If your application doesn't have one, use a message box or write the error to a log-file.
With regard to the problem in your code, all the other answers appear to be correct.