For-Loop a "Empty" Vector with negative iterator? - c++

Im trying to loop through the newest 10 Entries of a vector. The Size of the Vector can be anything between 0 and 100.
As easiest solution, i though starting the loop at vector.size() - 10; and then check inside if its not negative, i can access the vector object.
Sadly, it does not work (doesnt loop at all), but if i replace the same Code with hardcoded numbers, it works.
What im doing wrong, or where is the problem here?
for (int i = -10; i < 0; i++) {
std::cout << "Normal Loop: i = " << i << std::endl;
}
This works, but looping over a vector doesnt:
std::vector<int> myVector;
for (int i = myVector.size() - 10; i < myVector.size(); i++) {
std::cout << "Vector Loop: i = " << i << std::endl;
}
The first loop prints all 10 Numbers (From -10 to -1), but the second Loop doesnt print anything.
Since myVector.size() is 0 right now, it should be the same output as the first one

That's because std::vector::size() returns size_type as type, this type is unsigned. This means that i < myVector.size() compares two different types, int and unsigned int. The compiler will "promote" your int to an unsigned type. Because this int is negative and unsigned types can't hold negative values it will wrap around and you'll end up with a very big value and thus the loop condition is never met.
You could cast size() explicitly:
std::vector<int> myVector;
for (int i = myVector.size() - 10; i < static_cast<int>(myVector.size()); i++) {
std::cout << "Vector Loop: i = " << i << std::endl;
}
Or for a cleaner approach try using rbegin() and loop until rend() or until you've looped 10 times, something like:
std::vector<int> myVector;
//fill vector..
auto itr = myVector.rbegin();
int count = 10;
while(itr != myVector.rend() && count-- > 0)
{
//process.
++itr;
}

Related

signal: aborted (core dumped), making a two sum pair from a vector

This is the question I'm trying to solve:
Write findTwoSumPair, which takes in a vector of integers and a
target sum, and returns a pair that represents two distinct indices
of elements that sum up to the target value (with indexes sorted).
There are no explicit time complexity constraints here (i.e. algorithm
just needs to work as intended). Also make sure to handle empty input.
This is my main:
std::cout << "Q3" << std::endl;
std::vector<int> q3Input1{0, 2, 3, 4, 5};
std::pair<int, int> q3Out1 = findTwoSumPair(q3Input1, 6);
std::pair<int, int> q3Out2 = findTwoSumPair(q3Input1, 10);
std::cout << q3Out1.first << " " << q3Out1.second
<< std::endl; // should output 1 3
std::cout << q3Out2.first << " " << q3Out2.second
<< std::endl; // should output -1 -1
And this is the function causing me problems:
std::pair<int, int> findTwoSumPair(const std::vector<int>& vec, int targetSum) {
for (unsigned int i = 0; i < vec.size(); i++){
for(unsigned int j = i; i < vec.size();j++){
/*
if(targetSum == vec[i]+ vec[j]){
std::cout << vec[i] << vec[j];
}*/
}
}
return{vec[i],vec[j];
// throw std::logic_error("not implemented");
}
I was given the main.cpp so I'd like to not change it and there are the relevant library headers to make it run.
It only shows "Q3" for some reason. I commented out the content inside the if block because that was giving me the "signal: aborted (core dumped)" error.
As well as the "typo" in your code, where you are testing i in the inner for loop instead of j (the code you currently have will run that inner loop forever), there are some other issues in your function.
First, that inner loop should start at j = i + 1, otherwise a match will be found when any one value is exactly half the target (in your second test case, it will find a match for 5 + 5, giving index results of 4 and 4).
Second, as soon as a match is found, the function should return the current i and j values; then, if the outer loop terminates without a match being found, we can return the required {-1, -1} signal.
Here's a version of your function with the aforementioned (and some other) issues fixed:
std::pair<int, int> findTwoSumPair(const std::vector<int>& vec, int targetSum)
{
for (size_t i = 0; i < vec.size(); i++) {
for (size_t j = i + 1; j < vec.size(); j++) {// Start at i + 1 and test j (not i)
if (targetSum == vec[i] + vec[j]) {
return{ static_cast<int>(i), static_cast<int>(j) }; // Match found
}
}
}
return { -1, -1 }; // Not found.
}

C++ Persistent Vector, fill vector with data from a text file

i am currently trying to learn some C++ and now i got stuck in an exercise with vectors. So the task is to read ints from a text file and store them in the vector which should be dynamic.
I guess there is something wrong with the while-loop?
If I start this, the program fails and if I set the vector size to 6, I get
6 0 0 0 0 0 as output.
Thanks for any hints.
int main()
{
const string filename = "test.txt";
int s = 0;
fstream f;
f.open(filename, ios::in);
vector<int> v;
if (f){
while(f >> s){
int i = 0;
v[i] = s;
i = i+1;
}
f.close();
}
for(int i = 0; i < 6; i++){
cout << v[i] << "\n";
}
}
You don't grow the vector. It is empty and cannot hold any ints. You'll need to either resize it every time you want to add another int or you use push_back which automatically enlarges the vector.
You set i = 0 for every iteration so you would change the first value of the vector every iteration instead of the next one.
Go for:
v.push_back(s);
in your loop and
for(int i = 0; i < v.size(); i++) { // ...
Remark:
You normally don't hardcode vector sizes/bounds. One major point about using std::vector is its ability to behave dynamically with respect to its size. Thus, the code dealing with vectors should not impose any restrictions about the size of the vector onto the respective object.
Example:
for(int i = 0; i < 6; i++){ cout << v[i] << "\n"; }
requires the vector to have at least 6 elements, otherwise (less than 6 ints) you access values out of bounds (and you potentially miss elements if v contains more than 6 values).
Use either
for(int i = 0; i < v.size(); i++){ cout << v[i] << "\n"; }
or
for(std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++i)
{
cout << *i << "\n";
}
or
for(auto i = v.begin(); i != v.end(); ++i)
{
cout << *i << "\n";
}
or
for(int x : v){ cout << x << "\n"; }
or
for(auto && x : v){ cout << x << "\n"; }
or
std::for_each(v.begin(), v.end(), [](int x){ std::cout << x << "\n"; });
or variants of the above which possibly pre-store v.size() or v.end()
or whatever you like as long as you don't impose any restriction on the dynamic size of your vector.
The issue is in the line i= 0. Fixing that will give an issue in the line v[i] = s.
You always initialise i to 0 in the while loop, and that is responsible for the current output. You should shift it out of the while loop.
After fixing that, you have not allocated memory to that vector, and so v[i] doesn't make sense as it would access memory beyond bounds. This will give a segmentation fault. Instead, it should be v.push_back(i), as that adds elements to the end of a vector, and also allocates memory if needed.
If you are using std::vector you can use v.push_back(i) to fill this vector
Error is this line int i = 0;
because you declare i=0 every time in while-loop.
To correct this move this line outside from loop.
Note: this will work, if you declare v like normal array for example int v[101]
When you use std vectors you can just push element at the end of vector with v.push_back(element);
v[i] = s; //error,you dont malloc room for vector
change into : v.push_back(s);

for loop with different types c++

I have a for loop which i need to loop over different kinds of arrays, the first one is map<string,vector<string>> and the second is an integer array.
to implement this i did :
struct {map<string,vector<string>>::iterator it; int i; } s;
int k = 0;
for ( s.it = m.begin(), s.i = 0; s.it != m.end(), s.i < size; s.i+=2)
{
while (k != integer_array[s.i] && k < size)
{
s.it++;
k++;
}
if (k == integer_array[s.i])
{
cout << s.it.first << endl; // this line does not complie
k = 0;
s.it = m.begin();
}
}
explain of what i'm trying to do:
integer_array stores indexes and i'm trying to print the map value at index which stored in integer_array.
any suggestions?
I guess your problem is in the iterator.
Instead of:
cout << s.it.first << endl;
Try:
cout << s.it->first << endl;
The reason is that a STL iterator behaves like a pointer: if you want to access the value pointed, then you must dereference your iterator (either through operator * or through operator ->).
In the current case, the pointed value is a std::pair of std::string and std::vector, and you want to print the first std::string. Thus, you need to write it->first.

Find Two Largest Numbers, C++

I'm using this approach: First find the largest among 5 numbers then save the subscript of array of the largest number in an "ivariable" after displaying the largest number, do like this
array[ivariable] = 0 ;
so that first largest set to zero and its no longer here in the array.
And do the same again, find the largest, but I'm not getting what I'm trying to.
Its a logical error.
Thanks
#include <iostream>
using namespace std;
int main(void)
{
int counter, large,number,det_2, i , large3, det_3= 0;
int det[5] = {0,0,0,0,0};
for(int k(0); k < 5 ; k++)
{
cout << "Enter the number " << endl ;
cin >> det[k] ;
}
for( i; i<5; i++)
{
large = det[i] ;
if (large > det_2)
{
det_2= large ;
counter = i ;
}
else
{
}
}
cout << "Largest among all is " << det_2 << endl;
det[i] = 0 ;
for( int j(0); j<5; j++)
{
large3 = det[j] ;
if(large3 > det_3)
{
det_3= large3 ;
}
else
{
}
}
cout << "Second largest " << large3 << endl ;
system("PAUSE");
}
You've got possible syntax and initialization errors. Fix those first:
for(int k(0); k < 5 ; k++): I've never seen an integer initialized this way. Shouldn't it be:
for (int k = 0; k < 5; k++) ? (Same with the last loop.)
Also,
for( i; i<5; i++)
The variable i is uninitialized. Variables are not initialized to any default value in C++. Because you've left it uninitialized, it might execute 5 times, no times, or 25,899 times. You don't know.
This should be:
for (i = 0; i < 5; i++)
But the whole thing could probably be a bit clearer anyway:
#include <iostream>
using namespace std;
int main(void)
{
int largest = -1;
int second_largest = -1;
int index_of_largest = -1;
int index_of_second_largest = -1;
int det[5] = {0, 0, 0, 0, 0};
for (int i = 0; i < 5; i++)
{
cout << "Enter the number " << endl;
cin >> det[i]; // assuming non-negative integers!
}
for (int j = 0; j < 5; j++) // find the largest
{
if (det[j] >= largest)
{
largest = det[j];
index_of_largest = j;
}
}
for (int k = 0; k < 5; k++) // find the second largest
{
if (k != index_of_largest) // skip over the largest one
{
if (det[k] >= second_largest)
{
second_largest = det[k];
index_of_second_largest = k;
}
}
}
cout << "Largest is " << largest << " at index " << index_of_largest << endl;
cout << "Second largest is " << second_largest <<
" at index " << index_of_second_largest << endl;
return 0;
}
Always give your variables values before you use them
det_2 = det[0];
counter = 0;
for (i = 1; i < 5; i++)
first problem I saw was that you are iterating using i as an index, but you don't initialize i.
code should be:
for(i = 0; i<5; i++)
^^^^
same goes for det_2. You compare elements against it, but do not initialize it. You should set it to det[0] before the loop where you use it.
third problem: Your "set largest value to zero after printing" sounds like it is there so that you can apply the same algorithm the second time.
You should create an additional function that gives you the index of the largest element, and call it like this:
int index = find_largest_index(a);
cout << "largest element: " << a[index] << endl;
a[index] = 0;
cout << "second largest element: " << a[ find_largest_index(a) ] << endl;
GCC 4.7.3: g++ -Wall -Wextra -std=c++0x largest.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::cout << "Enter 5 numbers: ";
// Read 5 numbers.
std::vector<int> v;
for (auto i = 0; i < 5; ++i) {
int x = 0;
while (!(std::cin >> x)) {
// Error. Reset and try again.
std::cin.clear();
std::cin.ignore();
}
v.push_back(x);
}
// partition on element 3 (4th number)
std::nth_element(std::begin(v), std::next(std::begin(v), 3), std::end(v));
std::cout << "Two largest are: ";
std::copy(std::next(std::begin(v), 3), std::end(v), std::ostream_iterator<int>(std::cout, " "));
}
In the specific case of 5 elements, the algorithm you use is unlikely to make any real difference.
That said, the standard algorithm specifically designed for this kind of job is std::nth_element.
It allows you to find the (or "an", if there are duplicates) element that would end up on position N if you were to sort the entire collection.
That much is pretty obvious from the name. What's not so obvious (but is still required) is that nth_element also arranges the elements into two (or three, depending on how you look at it) groups: the elements that would short before that element, the element itself, and the elements that would sort after that element. Although the elements are not sorted inside of each of those groups, they are arranged into those groups -- i.e., all the elements that would sort before it are placed before it, then the element itself, then the elements that would sort after it.
That gives you exactly what you want -- the 4th and 5th elements of the 5 you supply.
As I said originally, in the case of just 5 elements, it won't matter much -- but if you wanted (say) the top 50000 out of ten million, choosing the right algorithm would make a much bigger difference.
nth_element isn't always suitable (or as efficient as it could be) as it needs to rearrange the input elements.
It's very common to want just the top two elements, and can be done efficiently in one pass by keeping the best and second-best values seen so far, and whenever a value you iterate over is better than the second-best, you'll either replace the second-best with it or the best, and in the latter case you also overwrite the best with the new value. That can look like this:
#include <utility>
template <typename It, typename EndIt, typename Less = std::less<>>
auto top_two(It it, EndIt end, Less less = Less{}) -> std::pair<It, It>
{
It first = it;
if (it == end || ++it == end)
return {first, end};
std::pair<It, It> results = less(*it, *first) ? std::pair{first, it} : std::pair{it, first};
while (++it != end)
if (less(*results.second, *it))
results.second = less(*results.first, *it)
? std::exchange(results.first, it) : it;
return results;
}
(See it running at http://coliru.stacked-crooked.com/a/a7fa0c9f1945b3fe)
I return iterators so the caller can know where in the input the top two elements are, should they care (e.g. to erase them from a container, or calculate their distance from begin(), or modify their values).
It you want the two lowest values, just pass std::greater<>{} as your "less" argument.
Some convenience functions to make it easier to call with containers or initializer_lists:
template <typename Container, typename Less = std::less<>>
auto top_two(const Container& c, Less less = Less{})
{
return top_two(begin(c), end(c), less);
}
template <typename T, typename Less = std::less<>>
auto top_two(const std::initializer_list<T>& il, Less less = Less{})
{
return top_two(begin(il), end(il), less);
}
If you want a general solution for the top-N elements, it's better to make N an argument and create a multiset of N top values (using a dereferencing comparison type), putting the initial N elements in, then whenever a new element is more than the **top_n.begin() value, do a top_n.insert(it); followed by top_n.erase(top_n.rbegin()); to drop the worst element: these operations are O(log N) so remain reasonably efficient even in pathological cases, such as input that is incrementing numbers.

Removing duplicate entries in an array (C++)

I'm having an issue in which a function that in theory should remove all duplicate values from an array doesn't work. Here's how it works:
I have two arrays, and then I populate them with random numbers
between 0 and 50 inclusive.
I sort the array values in order using a sort function
I then run my dedupe function
I sort the array values in order again
I then output the values in both arrays
The problem is, the loop in the dedupe function is ran 19 times regardless of how many duplicate entries it finds, which is extremely strange. Also, it still gives duplicates.
Any ideas? Thanks!
int* dedupe(int array[ARRAY_SIZE]) //remove duplicate array values and replace with new values.
{ bool dupe = false;
while(dupe!=true)
{
for(int j=0; j<ARRAY_SIZE; j++)
{ if(array[j] == array[j+1])
{ array[j] = rand();
array[j] = array[j] % 51;
dupe = false;
}
else { dupe = true; // the cout part is for debugging
cout << dupe << endl; }
}
} return array;
}
int main()
{
int a[9], b[9];
srand(time(0));
populate(b);
populate(a);
sort(a,ARRAY_SIZE);
sort(b,ARRAY_SIZE);
dedupe(a);
dedupe(b);
sort(a,ARRAY_SIZE);
sort(b,ARRAY_SIZE);
for(int i=0; i<10; i++)
{ cout << "a[" << i << "] = " << a[i] << "\t\t" << "b[" << i << "] = " << b[i] << endl; }
return 0;
}
Nothing suggested so far has solved the problem. Does anyone know of a solution?
You're not returning from inside the for loop... so it should run exactly ARRAY_SIZE times each time.
The problem that you want to solve and the algorithm that you provided do not really match. You do not really want to remove the duplicates, but rather guarantee that all the elements in the array are different, the difference being that by removing duplicates the number of elements in the array would be less than the size of the array, but you want a full array.
I don't know what the perfect solution would be (algorithmically), but one simple answer would be creating an array of all the values in the valid range (since the range is small), shuffling it and then picking up the first N elements. Think of this as using cards to pick the values.
const int array_size = 9;
void create_array( int (&array)[array_size] ) {
const int max_value = 51;
int range[max_value];
for ( int i = 0; i < max_value; ++i ) {
range[i] = i;
}
std::random_shuffle( range, range+max_value );
std::copy_n( range, array_size, array );
}
This is not the most efficient approach, but it is simple, and with a small number of elements there should not be any performance issues. A more complex approach would be to initialize the array with the random elements in the range, sort and remove duplicates (actually remove, which means that the array will not be full at the end) and then continue generating numbers and checking whether they are new against the previously generated numbers.
Simplest approach is just comparing with every other value which is linear time but on an array of 9 elements linear time is small enough not to matter.
you are doing it wrong at
array[j] = rand();
array[j] = array[j] % 51
It will always have 1 to ARRAY SIZE!!