I don't know why I get these rubish numbers in my vector container?
here is the code:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> ivec = {2,3,5,7};
std::vector<int>::iterator it = ivec.begin();
std::vector<int>::iterator pos = ivec.begin()+1;
ivec.insert(pos,444);
while(it != ivec.begin())
{
std::cout << *it << std::endl;
it++;
}
return 0;
}
here is the result :
0
0
370638864
22056
0
0
49
0
2
444
3
5
7
When you insert a value in to a container (a vector in this case) you can invalidate any iterator's you currently have if the vector needs to resize. If the vector doesn't resize only iterator's before the insertion remain valid. The past the end iterator is also invalidated.
Also, your while loop condition should be it != ivec.end( ).
That being said, make your life easy and just use a range-based for loop.
int main( ) {
std::vector vec{ 2, 3, 5, 7 };
vec.insert( vec.begin( ) + 1, 444 );
for ( auto value : vec ) {
std::cout << value << '\n';
}
// If you really want to use iterators you can do this.
// Do this after the insertion into the vector.
for ( auto it{ vec.begin( )}; it != vec.end( ); ++it ) {
std::cout << *it << '\n';
}
}
Related
I have one array like {7, 3, 1, 5, 2} for example. I want to get a max value from one index onwards, so the result should be like {7, 5, 5, 5, 2}. I just use a for loop like below. It throws strange heap overflow problem.
int maxProfit(vector<int>& prices) {
vector<int> maxRight;
int runningMax = 0;
for(auto i=(prices.size()-1);i>=0;i--){
if(runningMax < prices[i]){
runningMax = prices[i];
}
maxRight.push_back(runningMax);
}
maxRight.push_back(runningMax);
std::reverse(maxRight.begin(), maxRight.end());
......
But if i change to the below code, it works. Isn't the below code the same as the above one? I just changed the comparison of the index i to 0 or to 1.
int maxProfit(vector<int>& prices) {
vector<int> maxRight;
int runningMax = 0;
for(auto i=(prices.size()-1);i>=1;i--){
if(runningMax < prices[i]){
runningMax = prices[i];
}
maxRight.push_back(runningMax);
}
if(runningMax < prices[0]){
runningMax=prices[0];
}
std::reverse(maxRight.begin(), maxRight.end());
......
As was pointed out in a comment,
auto i=(prices.size()-1) , i is deduced to be unsigned value, and the condition i >= 0 is always true. You have accessing out of bounds of array.
Instead of using an index, use an iterator, in this case a std::vector::reverse_iterator.
for(auto it = prices.rbegin(); it != prices.rend(); ++it)
{
if(runningMax < *it)
{
runningMax = *it;
}
maxRight.push_back(runningMax);
}
As the variable i declared in the for loop
for(auto i=(prices.size()-1);i>=0;i--){
has the unsigned integer type std::vector<int>::size_type then you will get an infinite loop because when i is equal to 0 then the expression i-- will afain produces a non-negative number.
Another problem is that the for loop will again invoke undefined behavior if the passed vector is empty dues to the initialization in the declaration part of the for loop
auto i=(prices.size()-1)
because prices.size()-1 produces a positive value in this case.
In the second function implementation you forgot to push a calculated value for the first element of the vector prices. You just wrote after the loop
if(runningMax < prices[0]){
runningMax=prices[0];
}
that does not make a great sense.
`
You could write a separate function that returns the desired vector of maximum prices.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
std::vector<int> max_prices( const std::vector<int> &prices )
{
std::vector<int> maxRight;
maxRight.reserve( prices.size() );
for ( auto first = std::rbegin( prices), last = std::rend( prices );
first != last;
++first )
{
if ( maxRight.empty() )
{
maxRight.push_back( *first );
}
else
{
maxRight.push_back( std::max( maxRight.back(), *first ) );
}
}
std::reverse( std::begin( maxRight ), std::end( maxRight ) );
return maxRight;
}
int main()
{
std::vector<int> prices = { 7, 3, 1, 5, 2 };
auto maxRight = max_prices( prices );
for ( const auto &price : maxRight )
{
std::cout << price << ' ';
}
std::cout << '\n';
return 0;
}
The program output is
7 5 5 5 2
So.. I am trying to find the maximum value of a vector and its position in the vector. I am using a for loop, and it's working fine. My problem is, that if the maximum value appears more than once, I want to know all the positions in which it appears in the vector.. So, how could I manage this?
So far, this is the code I am using: (the vector called v has elements that I read from a file but I will not add that part of the code)
std::vector<double>v;
double maxvalue;
int position=0;
maxvalue = v[0];
for (unsigned int i=0; i<v.size(); i++){
if (v[i]> maxvalue){
maxvalue=v[i];
position= i;
}
}
You could modify your approach to keep a vector of indices where the maximum occurred:
#include <cfloat>
#include <iostream>
#include <utility>
#include <vector>
std::pair<double, std::vector<std::size_t>> FindMaxElements(std::vector<double> const& v)
{
std::vector<std::size_t> indices;
double current_max = -DBL_MAX;
for (std::size_t i = 0; i < v.size(); ++i)
{
if (v[i] > current_max)
{
current_max = v[i];
indices.clear();
}
if (v[i] == current_max)
{
indices.push_back(i);
}
}
return std::make_pair(current_max, indices);
}
int main()
{
auto result = FindMaxElements({1, 4, 7, 2, 7, 3});
std::cout << "max: " << result.first << '\n';
std::cout << "indices: ";
for (auto i : result.second)
std::cout << i << ' ';
}
Output
max: 7
indices: 2 4
Here is a two-pass version using the standard library (whereas it might be cleaner without it):
#include <vector>
#include <algorithm>
int main()
{
std::vector<double> v {/* fill it*/ };
std::vector<int> pos;
auto it = std::max_element(std::begin(v), std::end(v));
while (it != std::end(v))
{
pos.push_back(std::distance(std::begin(v), it));
it = std::find(std::next(it), std::end(v), *it);
}
//...
}
The function template below, find_maximums(), returns an std::vector<size_t> that contains the positions where the maximums are in the input vector. Note that it returns an empty vector of indexes if the input vector is empty.
template<typename T>
auto find_maximums(const std::vector<T>& v) {
std::vector<size_t> indexes;
for (auto it_max = std::max_element(v.begin(), v.end()); it_max != v.end();
it_max = std::find(it_max+1, v.end(), *it_max))
{
auto index = std::distance(v.begin(), it_max);
indexes.push_back(index);
}
return indexes;
}
As an example of use:
auto main() -> int {
std::vector<int> v = {11, 7, 3, 11, 0, 7, 1, 11, 11};
auto max_indexes = find_maximums(v);
if (max_indexes.empty())
return 1;
std::cout << "max: " << v[max_indexes.front()] << std::endl;
std::cout << "max at positions: ";
for (auto idx: max_indexes)
std::cout << idx << ' ';
std::cout << '\n';
}
It outputs:
max: 11
max at positions: 0 3 7 8
Passing a couple of iterators and a comparator
template <class It,
class Comp = std::less<typename std::iterator_traits<It>::value_type>>
auto max_elements_indices(It first, It last, Comp cmp = Comp{})
{
// This function returns a vector of indices, so to get the maximum, the caller
// should first check if the returned vector is empty and then use one of
// those indices to retrieve the value.
std::vector<std::size_t> indices;
if (first == last)
return indices;
// Using the first element instead of a sentinel value is easier to generalize
indices.push_back(0);
auto value = *first;
for (auto i = std::next(first); i != last; ++i)
{
// The most common case should be an element below the maximum
if ( cmp(*i, value) )
continue;
else
{
if ( cmp(value, *i) )
{
value = *i;
indices.clear();
}
indices.push_back(std::distance(first, i));
}
}
return indices;
}
It is testable here.
I have a vector. I need to delete the last 3 elements in it.
Described this logic. The program crashes. What could be the mistake?
vector<float>::iterator d = X.end();
for (size_t i = 1; i < 3; i++) {
if (i == 1) X.erase(d);
else X.erase(d - i);
}
If there are at least 3 items in the vector, to delete the last 3 items is simple -- just call pop_back 3 times:
#include <vector>
#include <iostream>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 3 && !v.empty(); ++i)
v.pop_back();
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
}
Output:
1 2
It is undefined behavior to pass the end() iterator to the 1-parameter erase() overload. Even if it weren't, erase() invalidates iterators that are "at and after" the specified element, making d invalid after the 1st loop iteration.
std::vector has a 2-parameter erase() overload that accepts a range of elements to remove. You don't need a manual loop at all:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
Live Demo
You could use a reverse_iterator:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<float> X = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
// start the iterator at the last element
vector<float>::reverse_iterator rit = X.rbegin();
// repeat 3 times
for(size_t i = 0; i < 3; i++)
{
rit++;
X.erase(rit.base());
}
// display all elements in vector X
for(float &e: X)
cout << e << '\n';
return 0;
}
There are few things to mention:
reverse_iterator rit starts at the last element of the vector X. This position is called rbegin.
erase requires classic iterator to work with. We get that from rit by calling base. But that new iterator will point to the next element from rit in forward direction.
That's why we advance the rit before calling base and erase
Also if you want to know more about reverse_iterator, I suggest visiting this answer.
First, X.end() doesn't return an iterator to the last element of the vector, it rather returns an iterator to the element past the last element of the vector, which is an element the vector doesn't actually own, that's why when you try to erase it with X.erase(d) the program crashes.
Instead, provided that the vector contains at least 3 elements, you can do the following:
X.erase( X.end() - 3, X.end() );
Which instead goes to the third last element, and erases every element after that until it gets to X.end().
EDIT: Just to clarify, X.end() is a LegacyRandomAccessIterator which is specified to have a valid - operation which returns another LegacyRandomAccessIterator.
This statement
if (i == 1) X.erase(d);
has undefined behavior.
And this statement tries to remove only the element before the last element
else X.erase(d - i);
because you have a loop with only two iterations
for (size_t i = 1; i < 3; i++) {
You need something like the following.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
auto n = std::min<decltype( v.size() )>( v.size(), 3 );
if ( n ) v.erase( std::prev( std::end( v ), n ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
The program output is
1 2
The definition of end() from cppreference is:
Returns an iterator referring to the past-the-end element in the vector container.
and slightly below:
It does not point to any element, and thus shall not be dereferenced.
In other words, the vector has no element that end() points to. By dereferencing that non-element thru the erase() method, you are possibly altering memory that does not belong to the vector. Hence ugly things can happen from there on.
It is the usual C++ convention to describe intervals as [low, high), with the “low” value included in the interval, and the “high” value excluded from the interval.
A comment (now deleted) in the question stated that "there's no - operator for an iterator." However, the following code compiles and works in both MSVC and clang-cl, with the standard set to either C++17 or C++14:
#include <iostream>
#include <vector>
int main()
{
std::vector<float> X{ 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f };
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
std::vector<float>::iterator d = X.end();
X.erase(d - 3, d); // This strongly suggest that there IS a "-" operator for a vector iterator!
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
return 0;
}
The definition provided for the operator- is as follows (in the <vector> header):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
However, I'm certainly no C++ language-lawyer, and it is possible that this is one of those 'dangerous' Microsoft extensions. I would be very interested to know if this works on other platforms/compilers.
how to shift elements of array from one column to another column by using pointer to pointer in c++
When I do this, it says "Reference to non-static member function must be called"
for (int i = 0; i < size; i++)
{
array[n]->my_data[i] = array[n]->my_arr[i+1];
}
Here are a couple of C++ ways to do it. The second one, using std::rotate, is to be preferred.
#include <algorithm>
#include <vector>
#include <iostream>
void show(const std::vector<int> & vec) {
for (auto v : vec) {
std::cout << v << " ";
}
std::cout << '\n';
}
int main() {
std::vector<int> vec{ 0,1,2,3,4,5,6,7,8,9 };
// Re-invent wheel
for (auto it = vec.begin() + 1; it != vec.end(); ++it) {
*(it - 1) = std::move(*it);
}
vec.pop_back();
show(vec);
// No wheel re-invention
std::rotate(vec.begin(), vec.begin() + 1, vec.end());
vec.pop_back();
show(vec);
}
If you want to use a fixed size array on the stack, this is the way. Do not use
array int[10];
#include <algorithm>
#include <array>
#include <string>
#include <iostream>
const int sz = 5;
void show(const std::array<std::string, sz> & vec) {
for (auto v : vec) {
std::cout << v << " ";
}
std::cout << '\n';
}
int main() {
std::array<std::string, sz> vec{ "zero", "one", "two", "three", "four" };
// Roll your own
for (auto it = vec.begin() + 1; it != vec.end(); ++it) {
std::swap(*(it - 1), *it);
}
show(vec);
// No wheel re-invention
std::rotate(vec.begin(), vec.begin() + 1, vec.end());
show(vec);
}
It should go without saying that the C++ way is not to use fixed arrays at all. You should prefer STL vector over fixed arrays whenever possible. That being said, this might have been an introductory assignment where you must re-invent the wheel so to speak. I’m assuming you are constrained to fixed arrays for whatever reason. If not, get rid of them!
You didn't specify what array[n] is or what what the size of my_data is, or what even my_data holds. I'm going to answer this assuming that my_data contains a bunch of integers and that you wanted to rotate every element in that array to the left by 1 "column", making the first element the new last. Here's how you could do it. You need to take care to not overrun your array length.
const size_t len{10};
int my_data[len] = {0,1,2,3,4,5,6,7,8,9};
int i, temp;
temp = my_data[0]; ///< temp copy of data at 0
for (i = 0; i != len-1; i++)
{
my_data[i] = my_data[i+1]; ///< shift left by 1
}
my_data[i] = temp; ///< old data at 0 goes to the new end
Input:
0 1 2 3 4 5 6 7 8 9
Output:
1 2 3 4 5 6 7 8 9 0
I ran into a problem where i need to delete the last elements of a vector until a certain condition is met (for sake of this example let it be the element is not zero)
I wrote this code, it does the trick -
auto next = vec.rbegin();
while (next != vec.rend())
{
auto current = next++;
if (*current == 0)
vec.pop_back();
else
break;
}
But i would much rather find an stl algorithm that i can use (i can use find_if and then erase, but i'd like to loop once through the elements that i remove...)
Also, i'm afraid i may be invoking some UB here, should i be worried?
Your code can be simplier:
while( !vec.empty() && vec.back() == 0 )
vec.pop_back();
Using std::remove or std::remove_if would remove all elements based by criteria, so you should use std::find_if as Vlad provided in his answer.
Here is an example. It uses the general idiom for erasing vectors
v.erase( std::remove( /*...*/ ), v.end() )
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::vector<int> v = { 1, 2, 3, 4, 5, 0, 0, 0 };
v.erase(
std::find_if( v.rbegin(), v.rend(),
[]( int x ) { return x != 0; } ).base(), v.end() );
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
return 0;
}
The output is
1 2 3 4 5