C++ linked List nodes not changing - c++

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 &current : 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 &current : first )
{
std::cout << current << ' ';
}
std::cout << '\n';
for ( const auto &current : second )
{
std::cout << current << ' ';
}
std::cout << '\n';
std::cout << '\n';
second.reverse();
for ( const auto &current : first )
{
std::cout << current << ' ';
}
std::cout << '\n';
for ( const auto &current : second )
{
std::cout << current << ' ';
}
std::cout << '\n';
std::cout << '\n';
merge( first, second );
for ( const auto &current : first )
{
std::cout << current << ' ';
}
std::cout << '\n';
for ( const auto &current : 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.

Related

How to convert a C++ STL vector iterator to a vector reverse iterator?

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

Flow of arguments(The way pair of arguments are sent) from the container to the binary predicate function in a certain algorithm

when we want an algorithm to behave based on our own requirements on a container.Then we create our very own Binary Predicate function,my code includes bool twice(int e1,int e2){ return e1*2 == e2} on list L ={30,50,15,10,20,80,90}in the below code,I've used adjacent_find(L.begin(),L.end(),twice) algorithm to find the pair of integers where the first one is twice the second.Here I am unable to understand how the passing of arguments takes place? does (30,50) is sent to binary predicate?if Yes,then what is the next pair of arguments that is sent?is it (30,15) then (30,10)---(30,90),or (50,15) then (15,10)---(80,90),How does the algorithm decides the flow in which arguments are send?what are they?Does the algorithm stops performing its respective task as soon as it encounters return value of binary predicate as 'true'?Could anyone explain me how the passing of arguments takes place between container elements and binary predicate ?
#include <iostream>
#include <algorithm>
#include <list>
bool twice(int e1,int e2)
{
return e1 * 2 == e2;
}
int main()
{
std::list<int> L ={30,50,15,10,20,80,90};
std::list<int>::iterator i;
i = std::adjacent_find(L.begin(),L.end(),twice);
if(i==L.end())
std::cout<<"There are not two adjacent elements where the second is twice the first.\n";
else
std::cout<<"Two adjacent elements where the second is twice the first are:"<<*(i++)<<" & "<<*(i);
return 0;
}
As the name of algorithm implies adjacent elements are considered. For the list from your example
{ 30, 50, 15, 10, 20, 80, 90 }
the adjacent elements are
( 30, 50 ), ( 50, 15 ), ( 15, 10 ), ( 10, 20 ), ( 20, 80 ), ( 80, 90 )
As soon as the first adjacent pair of elements that satisfies the binary predicate is found the algorithm stops its execution and returns the iterator that points to the first element of the pair.
Take into account that this statement
std::cout<<"Two adjacent elements where the second is twice the first are:"<<*(i++)<<" & "<<*(i);
results in undefined behavior because there is no sequence point between evalutions of these expressions *(i++) and *(i).
To understand how the algorithm works it is useful to write it yourself.
For example
#include <iostream>
#include <list>
#include <iterator>
template <typename ForwardIterator, typename BinaryPredicate>
ForwardIterator adjacent_find( ForwardIterator first, ForwardIterator last, BinaryPredicate binary_predicate )
{
auto next = first;
if ( first != last && ++next != last )
{
while ( next != last && not binary_predicate ( *first, *next ) )
{
++first;
++next;
}
}
return next == last ? next : first;
}
int main()
{
std::list<int> lst ={ 30, 50, 15, 10, 20, 80, 90 };
auto twice = []( const auto &e1, const auto &e2 )
{
return 2 * e1 == e2;
};
auto it = ::adjacent_find( std::begin( lst ), std::end( lst ), twice );
if ( it == std::end( lst ) )
{
std::cout << "There are not two adjacent elements where the second is twice the first.\n";
}
else
{
std::cout << "Two adjacent elements where the second is twice the first are: "
<< *it << " & " << *std::next( it ) << '\n';
}
}
The program output is
Two adjacent elements where the second is twice the first are: 10 & 20

next iterator after end() in std::list

#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.

C++ list in list

I have two lists
list<int> s;
list<std::list<int>> q;
and I did the following assignment
q.push_front(s);
How can I display the contents of q since this
for (q_iterator = q.begin(); q_iterator != q.end(); ++q_iterator)
for (s_iterator = q_iterator.begin(); s_iterator != q_iterator.end(); ++s_iterator)
cout << *s_iterator;
gives me an error?
You have to write the following way
for (q_iterator = q.begin(); q_iterator != q.end(); ++q_iterator)
for (s_iterator = q_iterator->begin(); s_iterator != q_iterator->end(); ++s_iterator)
cout << *s_iterator;
or the following way
for (q_iterator = q.begin(); q_iterator != q.end(); ++q_iterator)
for (s_iterator = ( *q_iterator ).begin(); s_iterator != ( *q_iterator ).end(); ++s_iterator)
cout << *s_iterator;
provided that q_iterator and s_iterator are already declared. Otherwise you could write for example
for ( auto q_iterator = q.begin; /*...*/ )
Also you can use the range based for statement. For example
for ( const auto &s : q )
{
for ( int x : s ) std::cout << x << ' ';
std::cout << std::endl;
}
You probably know it, but I just want to make sure you remember about a space between angle braces.
std::list<std::list<int> >

simple list in c++

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 ?