#include <iostream>
#include <list>
#include <deque>
int main( void )
{
std::deque< std::deque< int > > integers_lists ;
const std::list< int > list0 { 1 , 2 , 3 } ;
for ( auto current = std::next( list0.cbegin() )
; current != std::next( list0.cend() )
; ++ current ) integers_lists.emplace_back( list0.cbegin() , current ) ;
for ( const auto& sub : integers_lists )
{
for ( auto each : sub ) std::cout << each << " " ;
std::cout << "\n" ;
}
return 0;
}
does STL guarantee the correctness of current != std::next( list0.cend() ) expression in this case.?
and where exactly that's pointed in Standard.?
std::next( list0.end() ) is invalid in almost any context.
Even if you simplified your program to this:
int main() {
std::list<int> list0 { 1 , 2 , 3 } ;
auto iter = std::next(list0.end());
}
it would be invalid. You can compare against an .end() iterator, but you cannot dereference it and nor can you iterate past it via std::next. It's undefined behaviour.
If you want to use each item in the list once, simply do:
for(auto & reference_to_current : list0) {
/* ... */
}
or, if you insist on using iterators,
for(auto current = list0.begin()
; current != list0.end()
; ++ current)
{ /* ... */ }
And yes, that will include every item, including the last item. The .end() iterator is special - it doesn't point to the last item, it points to the next slot just after the last item. "one-past-the-end".
Finally, next(list0.begin()) skips the first item. Are you sure you want to skip the first item?
Update: if you do want to skip the first item, but use all other items, you can use
if(list0.empty()) {
/* Error, list must not be empty */
} else {
for(auto current = std::next(list0.begin()) // skip first item
; current != list0.end()
; ++ current)
{ /* ... */ }
}
The if is very important, because we must not call std::next(list0.begin()) if the list is empty.
Related
I am trying to reorder Linked List such that given linked list (Head),
L0 → L1 → … → Ln - 1 → Ln
changes to,
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
void reorderList(ListNode* head) {
ListNode* h=head;
map<int,ListNode*> allNodes;
int count=0;
while(h!=nullptr){
ListNode* temp=new ListNode(h->val);
allNodes[count]=temp;
count++;
h=h->next;
}
auto rItr=allNodes.rbegin();
auto itr=allNodes.begin();
head=nullptr;// tried with and without this line same result
while(itr->first!=rItr->first){
head=itr->second;
head=head->next;
head=rItr->second;
itr++;
rItr++;
head=head->next;
}
head=itr->second;
}
I am creating new nodes and storing them in the map, Why is the Linked List not getting updated?
Input [1,2,3,4,5]
Expected output:
[1,5,2,4,3]
Actual Output
[1,2,3,4,5]
That is no change
To make the assignment there is no need to allocate new nodes. Moreover it is inefficient and requires additional memory.
Pay attention to that within your function you are changing the pointer to the head node but the original pointer to the head node is passed to the function by value. That is the function deals with a copy of the value of the original pointer to the head node. Changing the copy does not influence on the value stored in the original pointer to the head node.
As an idea I can suggest the following approach to the assignment.
First, find the middle of the list. Using the middle split the list
into two lists.
Second, reverse the second list.
Third, combine the two lists in one list.
Here is a demonstrative program that shows the approach using the standard container std::forward_list that represents a singly-linked list (it is not a production code.:)).
#include <iostream>
#include <forward_list>
#include <iterator>
template <typename T>
typename std::forward_list<T>::const_iterator
find_middle( const std::forward_list<T> &list )
{
auto middle = std::begin( list );
for ( auto last = std::begin( list );
last != std::end( list ) && ( std::advance( last, 1 ), last != std::end( list ) );
std::advance( last, 1 ) )
{
std::advance( middle, 1 );
}
return middle;
}
template <typename T>
void merge( std::forward_list<T> &first, std::forward_list<T> &second )
{
for ( auto position = std::begin( first );
position != std::end( first ) && !second.empty(); )
{
position = first.insert_after( position, second.front() );
std::advance( position, 1 );
second.erase_after( second.before_begin() );
}
if ( !second.empty() )
{
first.insert_after( std::end( first ), std::begin( second ), std::end( second ) );
second.clear();
}
}
int main()
{
std::forward_list<int> first = { 1, 2, 3, 4, 5 };
for ( const auto ¤t : first )
{
std::cout << current << ' ';
}
std::cout << '\n';
std::cout << '\n';
auto middle = find_middle( first );
if ( middle != std::begin( first ) )
{
std::forward_list<int> second;
second.splice_after( second.before_begin(), first, middle, std::cend( first ) );
for ( const auto ¤t : first )
{
std::cout << current << ' ';
}
std::cout << '\n';
for ( const auto ¤t : second )
{
std::cout << current << ' ';
}
std::cout << '\n';
std::cout << '\n';
second.reverse();
for ( const auto ¤t : first )
{
std::cout << current << ' ';
}
std::cout << '\n';
for ( const auto ¤t : second )
{
std::cout << current << ' ';
}
std::cout << '\n';
std::cout << '\n';
merge( first, second );
for ( const auto ¤t : first )
{
std::cout << current << ' ';
}
std::cout << '\n';
for ( const auto ¤t : second )
{
std::cout << current << ' ';
}
std::cout << '\n';
}
return 0;
}
The program output is
1 2 3 4 5
1 2 3
4 5
1 2 3
5 4
1 5 2 4 3
So what you need is to write a function that finds the middle node (similar to the function find_middle shown in the demonstrative program). Then to write a function that splits a list based on the middle node into two lists. Then to write a function that reverses a singly-linked list. And then it will be easy to write a function that combines two list in one list.
I have used a nested for-loop to carry out insertion sort on a C++ STL <vector>. The first for-loop is over an iterator and the second one, over a reverse_itr.
I need to pass the index (iterator pointer value) from the first loop to the second. I have tried the following approach but it gives me this error
error: no match for ‘operator!=’ (operand types are
‘__gnu_cxx::__normal_iterator<int*, std::vector<int> >’ and
‘std::vector<int>::reverse_iterator’ {aka
‘std::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >’})
void insertionSort(int size, vector<int> arr) {
for(auto itr = arr.begin(); itr != arr.end() - 1; ++itr) {
int element = *(itr + 1);
cout << "Element being compared with preceding sub-array is : " << element << endl;
for(auto r_itr = (itr + 1); r_itr != arr.rend(); ++r_itr) {
if(*(r_itr+1) <= element) {
*r_itr = element;
break;
}
else {
*r_itr = *(r_itr+1);
}
}
}
}
I searched up quite a lot online, found a way to convert a reverse iterator to an iterator (using itr.base()) but not the other way round.
Also I am new to C++ STL and algorithms, please feel free to suggest any way to improve my code with respect to the "clean"-ness of code or the algorithm itself!
The class template std::vector has random access iterators. So there is no any need to convert a given "forward" iterator to a "reverse" iterator.
Just use with iterators the operator -- instead of the operator ++ or vice versa where it is required.
Pay attention to that the parameter size is not used in your function declared like
void insertionSort(int size, vector<int> arr);
If you want to sort a range from a vector then use two parameters declared as iterators that specify a range.
For example
void insertionSort( std::vector<int>::iterator first, std::vector<int>::iterator last );
Or you can write a more general function for vectors of any types using templates.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
#include <cstdlib>
#include <ctime>
void insertionSort( std::vector<int>::iterator first, std::vector<int>::iterator last )
{
if ( first != last )
{
for ( auto current = first; ++current != last; )
{
typename std::iterator_traits<decltype( current )>::value_type
value( *current );
auto prev = current, next = current;
while ( next != first && value < *--prev )
{
*next-- = *prev;
}
if ( next != current ) *next = value;
}
}
}
int main()
{
std::vector<int> v;
const int N = 10;
std::srand( ( unsigned int )std::time( nullptr ) );
std::generate_n( std::back_inserter( v ), N, [=]{ return std::rand() % N; } );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
insertionSort( std::begin( v ), std::end( v ) );
for ( const auto &item : v )
{
std::cout << item << ' ';
}
std::cout << '\n';
return 0;
}
Its output might look like
0 6 6 7 4 3 4 6 6 1
0 1 3 4 4 6 6 6 6 7
Try changing it to for(vector<int>::reverse_iterator r_itr(next(itr)); r_itr != arr.rend(); ++r_itr)
To expand on their working, reverse_iterator is not implemented the same as iterator. The logical and physical address for an iterator are the same but for reverse_iterator, the logical and physical address are not the same. For example: s.end() and s.rbegin() have the same physical address but *s.end() will give you an error but *s.rbegin() will give you the last value of the container s.
The code below will make things clear:
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> S{ 1, 2, 3 };
set<int>::iterator itr = S.find(2);
cout << *itr << endl;
set<int>::reverse_iterator r_itr(itr);
cout << *r_itr << endl;
cout << itr._Ptr << ' ' << r_itr.base()._Ptr << endl;
//S.erase(r_itr); // ERROR!
S.erase(r_itr.base());
for (int e : S)
cout << e << ' ';
}
On my machine, it produced the following output:
2
1
00F85DA8 00F85DA8
1 3
list<abc*> mylist ;
for( it = mylist.begin() ; it != mylist.end() ; ++it ) {
cout<<(*it)->getB()<<endl ;
if(*it == "0x9090" ) {
mylist.remove(*it);
}
}
I inserted 4 abc class object in the list , when i remove / erase a element from list using some condition , it leads to segmentation fault in next iteration .
Change the code to
list<abc*> mylist ;
for( it = mylist.begin() ; it != mylist.end() ; ) {
cout<<(*it)->getB()<<endl ;
if(*it == "0x9090" ) {
it = mylist.erase(*it);
}
else {
++it;
}
}
I think you meant erase instead of remove. remove erases all elements in the list for which iterator i satisfy the condition *i = value where value in your case is *it
Also this statement
if(*it == "0x9090" )
is invalid. You are comparing two pointers that can be equal or enuequal depending on options of the compiler if abc * is equivalent to char *.
Maybe it is a typo and there should be
if(**it == "0x9090" )
You should not iterate and remove (all list elements matching the value) - you might erase instead:
list<abc*> mylist ;
it = mylist.begin();
while(it != mylist.end()) {
cout<<(*it)->getB()<<endl ;
if(**it == "0x9090") it = mylist.erase(it);
else ++it;
}
I'm teaching my self C++.
I'm trying to combine polynomials. For this I have defined straightforward classes:
Polynomial<T>, Term<T> and Coefficient<T> (which may also just be
complex<T>) using simple value composition. I have defined the required operator overloads.
Polynomial's compare by sorting their terms (std::sort).
I am working on combineLikeTerms(); This method when called will first call
another member method that will sort this vector of Terms. For example:
4x^3 + 5x^2 + 3x - 4
would be a possible resulting sorted vector.
Question:
I am using two iterators on this vector and Im trying to merge adjacent terms
of the same order.
Lets say our initial vector after being sorted is this:
4x^3 - 2x^3 + x^3 - 2x^2 + x ...
after the function completes its iterations the temp stack vector would then
look like this 2x^3 + x^3 - 2x^2 + x ... if we look there are still like terms
this needs to be refactored again.
How do I do this? I'm thinking of using recursion.
// ------------------------------------------------------------------------- //
// setPolynomialByDegreeOfExponent()
// should be called before combineLikeTerms
template <class T>
void Polynomial<T>::setPolynomialByDegreeOfExponent()
{
unsigned int uiIndex = _uiNumTerms - 1;
if ( uiIndex < 1 )
{
return;
}
struct _CompareOperator_
{
bool operator() ( math::Term<T> a, Term<T> b )
{
return ( a.getDegreeOfTerm() > b.getDegreeOfTerm() );
} // operator()
};
stable_sort( _vTerms.begin(), _vTerms.end(), _CompareOperator_() );
} // setPolynomialByDegreeOfExponent
// ------------------------------------------------------------------------- //
// addLikeTerms()
template <class T>
bool Polynomial<T>::addLikeTerms( const Term<T>& termA, const Term<T>& termB, Term<T>& result ) const
{
if ( termA.termsAreAlike( termB ) )
{
result = termA + termB;
return true;
}
return false;
} // addLikeTerms
// ------------------------------------------------------------------------- //
// combineLikeTerms()
template <class T>
void Polynomial<T>::combineLikeTerms()
{
// First We Order Our Terms.
setPolynomialByDegreeOfExponent();
// Nothing To Do Then
if ( _vTerms.size() == 1 )
{
return;
}
Term<T> result; // Temp Variable
// No Need To Do The Work Below This If Statement This Is Simpler
if ( _vTerms.size() == 2 )
{
if ( addLikeTerms( _vTerms.at(0), _vTerms.at(1) )
{
_vTerms.clear();
_vTerms.push_back( result );
}
return;
}
// For 3 Ore More Terms
std::vector<Term<T>> vTempTerms; // Temp storage
std::vector<Term<T>>::iterator it = _vTerms.begin();
std::vector<Term<T>>::iterator it2 = _vTerms.begin()+1;
bool bFound = addLikeTerms( *it, *it2, result );
while ( it2 != _vTerms.end() )
{
if ( bFound )
{
// Odd Case Last Three Elems
if ( (it2 == (_vTerms.end()-2)) && (it2+1) == (_vTerms.end()-1)) )
{
vTempTerms.push_back( result );
vTempTerms.push_back( _vTerms.back() );
break;
}
// Even Case Last Two Elems
else if ( (it2 == (_vTerms.end()-1)) && (it == (_vTerms.end()-2)) )
{
vTempTerms.push_back( result );
break;
}
else
{
vTempTerms.push_back( result );
it += 2; // Increment by 2
it2 += 2; "
bFound = addLikeTerms( *it, *it2, result );
}
}
else {
// Push Only First One
vTempTerms.push_back( *it );
it++; // Increment By 1
it2++; "
// Test Our Second Iterator
if ( it2 == _vTerms.end() )
{
vTempTerms.push_back( *(--it2) ); // same as using _vTerms.back()
}
else
{
bFound = addLikeTerms( *it, *it2, result );
}
}
}
// Now That We Have Went Through Our Container, We Need To Update It
_vTerms.clear();
_vTerms = vTempTerms;
// At This point our stack variable should contain all elements from above,
// however this temp variable can still have like terms in it.
// ??? Were do I call the recursion and how do I define the base case
// to stop the execution of the recursion where the base case is a
// sorted std::vector of Term<T> objects that no two terms that are alike...
// I do know that the recursion has to happen after the above while loop
} // combineLikeTerms
Can someone help me find the next step? I'd be happy to hear about any bugs/efficiency issues in the code shown.
I love c++
Here's my take on it in modern C++.
Note the extra optimization of dropping terms with an effective coefficient of zero
Self contained sample: http://liveworkspace.org/code/ee68769826a80d4c7dc314e9b792052b
Update: posted a c++03 version of this http://ideone.com/aHuB8
#include <algorithm>
#include <vector>
#include <functional>
#include <iostream>
template <typename T>
struct Term
{
T coeff;
int exponent;
};
template <typename T>
struct Poly
{
typedef Term<T> term_t;
std::vector<term_t> _terms;
Poly(std::vector<term_t> terms) : _terms(terms) { }
void combineLikeTerms()
{
if (_terms.empty())
return;
std::vector<term_t> result;
std::sort(_terms.begin(), _terms.end(),
[] (term_t const& a, term_t const& b) { return a.exponent > b.exponent; });
term_t accum = { T(), 0 };
for(auto curr=_terms.begin(); curr!=_terms.end(); ++curr)
{
if (curr->exponent == accum.exponent)
accum.coeff += curr->coeff;
else
{
if (accum.coeff != 0)
result.push_back(accum);
accum = *curr;
}
}
if (accum.coeff != 0)
result.push_back(accum);
std::swap(_terms, result); // only update if no exception
}
};
int main()
{
Poly<int> demo({ { 4, 1 }, { 6, 7 }, {-3, 1 }, { 5, 5 } });
demo.combineLikeTerms();
for (auto it = demo._terms.begin(); it!= demo._terms.end(); ++it)
std::cout << (it->coeff>0? " +" : " ") << it->coeff << "x^" << it->exponent;
std::cout << "\n";
}
You need to look at the polynomial as a sequence of pairs (coefficient,variable):
[(coefficient1,variable1),(coefficient2,variable2),(coefficient3,variable3),...]
As you describe, you iterate through this from left to right, combining two adjacent pairs into one whenever the variable part is identical (this of course assumes that the list has already been sorted by the variable part!).
Now what happens when there are three or more elements in this list that share their variables? Well, then just keep combining them. There is no need for recursion or anything complicated, really.
At any point during the iteration you combine the variable part of the current pair with the variable part last seen. If they are identical, you combine them and simply continue. If the next pair you get still has the same variable part as the one last seen, well then you combine them again. If you do this correctly, there shouldn't be any duplicates left.
Here is an example of how to do this. It works by creating a new pair list, then iterating through the input list, for each item of the input list it decides whether to either combine it with the item last pushed to the new list, or by adding a new element to the new list:
#include <utility>
#include <vector>
#include <iostream>
typedef std::vector<std::pair<float,std::string>> Polynomial;
Polynomial combine_like_terms(const Polynomial &poly)
{
if (poly.empty())
return poly;
/* Here we store the new, cleaned-up polynomial: */
Polynomial clean_poly;
/* Now we iterate: */
auto it = begin(poly);
clean_poly.push_back(*it);
++it;
while (it != end(poly)) {
if (clean_poly.back().second == it->second)
clean_poly.back().first += it->first; // Like term found!
else
clean_poly.push_back(*it); // Sequence of like-terms ended!
++it;
}
return clean_poly;
}
int main()
{
Polynomial polynomial {
{ 1.0 , "x^2" },
{ 1.4 , "x^3" },
{ 2.6 , "x^3" },
{ 0.2 , "x^3" },
{ 2.3 , "x" },
{ 0.7 , "x" }
};
Polynomial clean_polynomial = combine_like_terms(polynomial);
for (auto term : clean_polynomial)
std::cout << '(' << term.first << ',' << term.second << ")\n";
std::cout.flush();
return 0;
}
You can easily make this templated again if you need to – I used float for the coefficients and strings for the variable part. It's really just a code example to show how this can be done easily without recursion or lots of iterators used in parallel.
Oh, and the code is written for C++11. Again, it's just a model and can be adjusted for C++03.
explicit list(
const A& Al = A( )
);
explicit list(
size_type n,
const T& v = T( ),
const A& Al = A( )
);
list(
const list& x
);
list(
const_iterator First,
const_iterator Last,
const A& Al = A( )
);
#include <list>
using namespace std;
list<Node> my_list;
int index = 0;
for ( list<Node>::iterator cursor = my_list.begin();
it!= my_list.end(); ++ cursor, ++ index ) {
cout << "index: " << index << “ value: “ << cursor->data() << endl;
}
At least based on what you have here, the problem isn't with how you traverse the list -- it's with using a list at all. You're asking for random access to the data, which means you should probably be using something like a vector or a deque instead of a list.
I really can't tell what this is trying to do, but you have a possible segfault in your inner loop:
for ( cursor = head_ptr; cursor !=NULL ||count<i; cursor=cursor->link() )
{
count++;
}
Your termination condition indicates that if count < i, you would keep looping even if cursor == NULL; when cursor=cursor->link() executes, you would try to dereference NULL.
Perhaps you meant cursor !=NULL && count<i ?