What is wrong with my code for reversing a linked list?
void rev(node* &head)
{
int flag=0;
node* head1=NULL;
while(head->next!=NULL)
{
node* temp1=head;
node* temp2=head;
while(temp1->next!=NULL)
{
temp2=temp1;
temp1=temp1->next;
}
if(flag==0)
{
head1=temp1;
flag++;
}
temp1->next=temp2;
temp2->next=NULL;
}
head=head1;
delete head1;
}
I was trying to solve a standard problem of reversing a link list. So i tried implementing this approach, however it seems to be going into infite loop, I am unable to understad why.
Your function is invalid.
For example the passed pointer head can be equal to nullptr. In this case this while loop
while(head->next!=NULL)
already can invoke undefined behavior.
Or there is nothing to delete in the list but the function has these statements
head=head1;
delete head1;
that do not make sense.
Even if to remove the statement with the call of delete nevertheless this does not make the function correct. For example if the list contains only one node then this while loop
while(head->next!=NULL)
will not be executed. As a result the pointer head will be set to NULL due to this statement after the loop
head=head1;
because before the loop the pointer head1 is set to NULL
node* head1=NULL;
Also it seems in this nested while loop
while(temp1->next!=NULL)
{
temp2=temp1;
temp1=temp1->next;
}
you are trying to find the last node in the list that at least is inefficient.
And your function is unclear and too complicated.
To write the function it is enough to learn the standard C++ function std::exchange declared in header <functional> that will make the code of the function more simpler and clear.
Here is a demonstration program that shows how the function that reverses a singly-linked list can be implemented.
#include <iostream>
#include <functional>
#include <iterator>
struct node
{
int data;
node *next;
};
void clear( node * &head )
{
while ( head ) delete std::exchange( head, head->next );
}
void assign( node * &head, const int a[], size_t n )
{
clear( head );
for (node **current = &head; n--; current = &( *current )->next)
{
*current = new node{ *a++, nullptr };
}
}
std::ostream & display( const node *const &head, std::ostream &os = std::cout )
{
for (const node *current = head; current != nullptr; current = current->next)
{
os << current->data << " -> ";
}
return os << "null";
}
void reverse( node * &head )
{
for ( node *current = head, *previous = nullptr; current != nullptr; previous = head )
{
head = std::exchange( current, current->next );
head->next = previous;
}
}
int main()
{
node *head = nullptr;
const int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
assign( head, a, std::size( a ) );
display( head ) << '\n';
reverse( head );
display( head ) << '\n';
clear( head );
}
The program output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
As you can see the function has only one for loop the compound statement of which contains only two statements
void reverse( node * &head )
{
for ( node *current = head, *previous = nullptr; current != nullptr; previous = head )
{
head = std::exchange( current, current->next );
head->next = previous;
}
}
Without using the standard function std::exchange the function that reverses a list will have one more statement as for example
void reverse( node * &head )
{
for ( node *current = head, *previous = nullptr; current != nullptr; previous = head )
{
head = current;
current = current->next;
head->next = previous;
}
}
First, a mini code review:
//
// Bigger issues implied by this function are that it is not a very good
// linked list, likely an extremely basic C-style list. However, that is
// beyond the scope of this question.
//
void rev(node* &head)
{
int flag=0; // Unnecessary
node* head1=NULL; // Prefer nullptr
while(head->next!=NULL)
{
node* temp1=head;
node* temp2=head; // Choose better names
while(temp1->next!=NULL) // Traverse the entire list at every iteration
{
temp2=temp1;
temp1=temp1->next;
}
if(flag==0)
{
head1=temp1;
flag++;
}
temp1->next=temp2; // Always and only swaps the last two elements
temp2->next=NULL;
// Never updates head in the loop; loop is infinite
}
head=head1;
delete head1; // head1 was pointing to a valid node; you just nuked your
// entire list
}
The algorithm is quite simple, and one that reveals itself when the problem is drawn using paper and pencil. You just need to make the arrows point the other way, and reassign the head. You are attempting that, but you don't change any pointers except for the final two nodes. You need to be changing them as you move through the list.
The special head check and flag are unnecessary. You will naturally arrive at the tail and can reassign head when you do so.
Here's the reworked algorithm:
#include <iostream>
struct node {
int data;
node* next;
node(int d) : data(d), next(nullptr) {}
};
//
// Bigger issues implied by this function is that it is not a very good
// linked list, likely an extremely basic C-style list. However, that is
// beyond the scope of this question.
//
void rev(node*& head) {
node* prev = nullptr;
node* curr = head;
node* next = nullptr; // Not immediately assigned to account for
// empty list.
while (curr) {
next = curr->next; //
curr->next = prev; // This order of operations is very important
prev = curr; //
curr = next; //
}
head = prev;
}
int main() {
node* list = new node{1};
list->next = new node{2};
list->next->next = new node{3};
list->next->next->next = new node{4};
list->next->next->next->next = new node{5};
node* walker = list;
std::cout << "Original list: ";
while (walker != nullptr) {
std::cout << walker->data << ' ';
walker = walker->next;
}
std::cout << '\n';
rev(list);
std::cout << "Reversed list: ";
walker = list;
while (walker != nullptr) {
std::cout << walker->data << ' ';
walker = walker->next;
}
std::cout << '\n';
// On the one hand, I don't delete my nodes. On the other,
// the program is ending and the OS will clean up my mess.
// This is generally a bad practice.
}
Output:
❯ ./a.out
Original list: 1 2 3 4 5
Reversed list: 5 4 3 2 1
While it would require more code, a proper C++ linked list class would be strongly preferred to avoid the downright silly initialization required in main().
And I understand that this code is likely just to understand this particular algorithm, but the C++ standard library does provide both singly and doubly linked lists, both of which are trivial to reverse.
Related
I've come across a problem in dynamic programming in which we are asked to delete nodes of a circular LinkedList, in the following manner.
Delete the first node then skip one and delete the next, then skip two and delete the next, then skip three and delete the next and it continues until we are left with only one node, and that one node is our answer.
For example, if we have 5 nodes, then the nodes will be deleted in the following order – 1 3
2 5 4, and the last node would be 4.
Similarly, if we have 4 nodes, then the nodes will be deleted in the following order – 1 3 4
2, and the last node would be 2.
This is a screenshot of the part of the code that requires improvement
using this code in c++, I've been successful in solving the problem but I want to free the memory using delete command as I delink a node. Can anyone please help me to solve this problem by improving this code (while using minimal memory)?
The node can be deleted by declaring another pointer, but that would only increase the memory usage, which I don't want at the moment.
The entire code is given below
#include<iostream>
using namespace std;
class linked {
public:
int x;
linked* next;
//methods
linked(int p); //constructor
static void insert(linked*& head, int p);//method to insert new node
static int print(linked* head);//method to print the result
static void del(linked*head, int size) {//method to delete all the undesired nodes
linked* temp = head;
while (temp->next != head) {//traversing until we find the node just behind the node we want to del
temp = temp->next;
}
for(int i=1;i < size;i++) {
for (int k = 1; k < i; k++) {//del nodes with increment
temp = temp->next;
}
temp->next = temp->next->next; //delinking the
}
}
};
int main() {
int no_of_nodes;
cout << "enter the number of nodes you want to have" << endl;
cin >> no_of_nodes;
linked* head = new linked(1);
for (int i = 1; i <= no_of_nodes; i++) {
linked::insert(head, i);//for inserting nodes, as desired by the user
}
linked::del(head, no_of_nodes);
cout<< linked::print(head);
}
linked::linked(int p) {
x = p;
next = NULL;
}
void linked::insert(linked*& head, int p) {
linked* temp = head;
linked* n = new linked(p);//for the new node
if (p == 1) {
head->next = head;
return;
}
while (temp->next != head) {
temp = temp->next;
}
temp->next = n;
n->next = head;
}
int linked::print(linked* head) {
linked* temp = head;
for (int i = 0; i < 25; i++) {//this can go longer(or shorter), i limited it to 25 only, just to ensure that it is a circular linked list
temp = temp->next;
if (temp == temp->next) {
return temp->x;
}
}
cout << endl;
}
P.S. The problem was taken from ICPC Asia Topi 2022, link: (https://giki.edu.pk/wp-content/uploads/2022/03/ICPC_Day_2.pdf)
It seems neither professional programmer are going to help you.:)
So we, beginners, should help each other.:)
You should declare a class of the circular singly-linked list with non-static member functions.
As for the task to remove all elements from the circular singly-linked list except one using the described algorithm then I can suggest the following approach.
At first within the function remove the cycling. This will make easy to remove elements from the circular singly-linked list.
After all elements except one will be removed then restore the cycling.
Here is a demonstration program.
#include <iostream>
#include <utility>
#include <stdexcept>
class CircularList
{
private:
struct Node
{
int data;
Node *next;
} *head = nullptr;
public:
CircularList() = default;
CircularList( const CircularList & ) = delete;
CircularList &operator =( const CircularList & ) = delete;
~CircularList()
{
clear();
}
void clear()
{
if (head)
{
Node *current = head;
do
{
delete std::exchange( current, current->next );
} while (current != head);
head = nullptr;
}
}
void insert( int data )
{
Node *new_node = new Node{ data };
if (not head)
{
new_node->next = new_node;
head = new_node;
}
else
{
Node *current = head;
while (current->next != head) current = current->next;
new_node->next = head;
current->next = new_node;
}
}
const int & top() const
{
if (not head)
{
throw std::out_of_range( "Error. The list is empty." );
}
return head->data;
}
void remove_except_one()
{
if (head)
{
Node *last = head;
while (last->next != head) last = last->next;
last->next = nullptr;
Node **current = &head;
for (size_t n = 0; head->next != nullptr; ++n)
{
for (size_t i = 0; i != n; i++)
{
current = &( *current )->next;
if (*current == NULL) current = &head;
}
Node *tmp = *current;
// The statement below is uncommented for the debug pyrpose.
std::cout << ( *current )->data << '\n';
*current = ( *current )->next;
if (*current == nullptr) current = &head;
delete tmp;
}
head->next = head;
}
}
friend std::ostream &operator <<( std::ostream &os, const CircularList &list )
{
if (list.head)
{
const Node *current = list.head;
do
{
os << current->data << " -> ";
current = current->next;
} while (current != list.head);
}
return os << "null";
}
};
int main()
{
CircularList list;
for (int i = 0; i < 5; i++)
{
list.insert( i + 1 );
}
std::cout << "The list: ";
std::cout << list << '\n';
list.remove_except_one();
std::cout << "The list: ";
std::cout << list << '\n';
list.clear();
std::cout << '\n';
for (int i = 0; i < 4; i++)
{
list.insert( i + 1 );
}
std::cout << "The list: ";
std::cout << list << '\n';
list.remove_except_one();
std::cout << "The list: ";
std::cout << list << '\n';
}
The program output is
The list: 1 -> 2 -> 3 -> 4 -> 5 -> null
1
3
2
5
The list: 4 -> null
The list: 1 -> 2 -> 3 -> 4 -> null
1
3
4
The list: 2 -> null
Within the function remove_except_one this statement
std::cout << ( *current )->data << '\n';
is present for the debug purpose only. You may remove or comment it if you want.
There are some problems with your code:
1) empty list should be nullptr
In main:
linked* head = new linked(1);
should be
linked* head = nullptr;
You start with an empty list. You do not know what data you will insert first and you assume the first value inserted will be 1. With this change you also have to change your insert:
if (p == 1) {
has to check
if (head == nullptr) {
2) replace head with tail
In a circular single linked list you always need the previous node to delete a node or to insert at the head. That means you have to traverse the whole list when given the head to find the previous. This is rather slow, so store the tail of the list instead. Then the head is tail->next and you can delete the head or insert at the head directly.
3) del breaks head
static void del(linked*head, int size) {
If this deletes the first node in the list then the head the caller passed in becomes a dangling pointer. There is no way to update the pointer the caller holds for the list. Just like with insert you need to pass in a reference:
static void del(linked*&head, int size) {
Now for your problem of how to delete the node without extra memory:
You can't. You always need extra memory to temporarily store the node to be deleted while you fix up the links in the list and then delete it. You already needed that extra memory to find the tail of the list and you called it temp.
static void del(linked*&tail) {
if (tail == nullptr) return; // no list, nothing to delete
for (std::size_t skip = 0; tail->next != tail; ++skip) { // keep going till only one node is left
for(std::size_t i = 0; i < skip; ++i) tail = tail->next; // skip nodes
// delete node
linked* temp = tail->next;
tail->next = tail->next->next;
delete temp;
}
}
I'm creating a linked list from another linked list. But second linked list is not getting formed and there's a memory leak message on running the program.
Here's a section of the code that's troubling-
Node *rearrangeLinkedList(Node *head){
printLinkedList(head);
int lengthoflist = 0;
Node *temp = head;
while (temp!=NULL)
{
lengthoflist++;
temp=temp->next;
}
Node *secondList = NULL;
// just a variable node to store the head of second linked list-
Node *headOfSecondList = secondList;
int count=1;
while (count<=lengthoflist/2)
{
Node *temproary = new Node();
temproary->data=head->data;
temproary->next=NULL;
secondList=temproary;
secondList=secondList->next;
head=head->next;
count++;
}
printLinkedList(headOfSecondList);
}
printLinkedList() function is perfectly printing out the incoming list but not the second linked list.
After
Node *secondList = NULL;
Node *headOfSecondList = secondList;
you don't modify headOfSecondList any more. It will still be NULL when you call
printLinkedList(headOfSecondList); // => printLinkedList(NULL);
But you have another error in the copy-function:
while (count<=lengthoflist / 2)
{
Node *temproary = new Node();
temproary->data=head->data;
temproary->next=NULL;
secondList=temproary; // assign secondList
secondList=secondList->next; // secondList->next is temporary->next is NULL!!
head=head->next;
count++;
}
Here you create a bunch of nodes that all have a next of NULL. You do indeed leak memory here. secondList gets set to NULL at the end of each iteration and when temporary goes out of scope you don't have any pointers to the allocated memory left.
The following should work
// Build first node
Node *secondList = new Node();
secondList->data = head->data;
// advance by one
head = head->next;
// Now this points to the real head instead of NULL
Node *headOfSecondList = secondList;
int count=1;
while (count<=lengthoflist / 2 - 1 ) // -1 since we already handled the head above
{
Node *temproary = new Node(); // new node
temproary->data = head->data; // set data
temproary->next = NULL; // we have no next yet
secondList->next = temproary; // append temporary to secondList
secondList = secondList->next; //advance secondList
head = head->next; // advance head
count++;
}
printLinkedList(headOfSecondList);
I have skipped some validation here, but I hope the basic concept is clearer now.
If I have understood correctly the function tries to build a new list from the first half of nodes of an existed list.
If so then there is no need to calculate the number of nodes in the source list. This is inefficient.
You declared the function having the return type Node *.
Node *rearrangeLinkedList(Node *head );
but the function returns nothing.
Within the function the variable headOfSecondList is set once to nullptr and is never changed.
Node *secondList = NULL;
Node *headOfSecondList = secondList;
Within the while loop new nodes are not chained in a list. There is always changed the variable secondList and its data member next is always set to NULL. So there are numerous memory leaks.
while (count<=lengthoflist/2)
{
Node *temproary = new Node();
temproary->data=head->data;
temproary->next=NULL;
secondList=temproary;
secondList=secondList->next;
head=head->next;
count++;
}
The function can be written the following way.
Node * rearrangeLinkedList( Node *head )
{
Node *new_head = nullptr;
Node **tail = &new_head;
Node *first = head, *current = head;
while ( current != nullptr && ( current = current->next ) != nullptr )
{
current = current->next;
*tail = new Node();
( *tail )->data = first->data;
( *tail )->next = nullptr;
first = first->next;
tail = &( *tail )->next;
}
return new_head;
}
To demonstrate the approach without counting the number of nodes in the source list that as I already pointed out is inefficient here is a demonstrative program with a class template List.
#include <iostream>
template <typename T>
class List
{
private:
struct Node
{
T data;
Node *next;
} *head = nullptr;
public:
List() = default;
~List()
{
while ( head )
{
Node *current = head;
head = head->next;
delete current;
}
}
List( const List<T> & ) = delete;
List<T> & operator =( const List<T> & ) = delete;
void push_front( const T &data )
{
head = new Node { data, head };
}
List<T> & extract_half( List<T> &list ) const
{
Node **tail = &list.head;
while ( *tail ) tail = &( *tail )->next;
Node *first = this->head, *current = this->head;
while ( current != nullptr && ( current = current->next ) != nullptr )
{
current = current->next;
*tail = new Node { first->data, nullptr };
first = first->next;
tail = &( *tail )->next;
}
return list;
}
friend std::ostream & operator <<( std::ostream &os, const List &list )
{
for ( Node *current = list.head; current; current = current->next )
{
os << current->data << " -> ";
}
return os << "null";
}
};
int main()
{
List<int> list1;
const int N = 10;
for ( int i = N; i != 0; )
{
list1.push_front( --i );
}
std::cout << list1 << '\n';
List<int> list2;
list1.extract_half( list2 );
std::cout << list1 << '\n';
std::cout << list2 << '\n';
return 0;
}
The program output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
0 -> 1 -> 2 -> 3 -> 4 -> null
I am trying to create sorted linked list = sorting it while creating it. Idea is simple , insert a node - and check if previous is smaller , if so check previous of previous and so on until it finds its spot. I have created this piece of code.
struct Node{
Node *prev;
Node *next;
int value;
};
struct List{
Node *head = nullptr;
Node *tail = nullptr;
};
Here i created a node , and a "holder" for the list = reference to first and last item of the list.
void insertNode(Node *&head,Node *&tail, int value ){
Node *tmp = new Node;
tmp -> prev = nullptr;
tmp -> next = nullptr;
tmp -> value = value;
head = tmp;
tail = tmp;
}
this function checks if list is empty , if yes , it inserts node to head and tail ( e.g head = tail = there is only one node in list );
What troubles me is function to insert a node
void insertIt(Node *&head , Node *&tail , int value){
if( head == nullptr){
insertNode(head,tail,value);
}
else{
Node *tmp = new Node;
tmp -> value = value;
if( value < tail -> value){
while(value < tail -> prev -> value){
tail = tail -> prev;
if( tail -> prev == nullptr){
tmp -> next = head;
tmp -> prev = nullptr;
head -> prev = tmp;
head = tmp;
return;
}
}
tail -> prev -> next = tmp;
tmp -> prev = tail -> prev;
tmp -> next = tail;
tail -> prev = tmp;
}else{
tmp -> next = nullptr;
tmp ->prev = tail;
tail -> next = tmp;
tail = tmp;
}
}
}
If list is empty , it invokes insertNode() , if value of the node is smaller than value of previous node , it crawls the list to find its spot.
This piece code works only if the first node inserted is also a smallest node there will be. e.g
insertIt(list.head , list.tail , -1);
insertIt(list.head , list.tail , 0);
insertIt(list.head , list.tail , 7);
insertIt(list.head , list.tail , 1);
insertIt(list.head , list.tail , 2);
insertIt(list head , list.tail , 2);
works and if i print the list it is nice sorted. but
insertIt(list.head , list.tail , -2);
insertIt(list.head , list.tail , -1);
insertIt(list.head , list.tail , 7);
insertIt(list.head , list.tail , 1);
insertIt(list.head , list.tail , 2);
insertIt(list.head , list.tail , 2);
the first node isnt the smallest node , it crashes the program. I thought it was i was comparing a value to nullptr so i added the piece of code which you can see in insertIt() function and that is
if( tail -> prev == nullptr){
tmp -> next = head;
tmp -> prev = nullptr;
head -> prev = tmp;
head = tmp;
return;
}
This checks if the node is a head , and swap head with new node , making new node new head.
Why does it crashes code? I failed to find a reasonable answer to this. Also , how could I improve my "algorithm" to make it more effective?
When iterating over the list to find the position to insert a new node, you do:
tail = tail -> prev;
But the tail variable is passed by a reference, that is you modify the tail member of yout List object, thus destroying its consistency.
Use another temporary variable, named, say current or position to walk along the list, and don't modify tail unless you're appending a new node at the end of the list.
EDIT example approach
struct Node {
Node(int val);
Node *prev;
Node *next;
int value;
};
struct List{
List() : head(nullptr), tail(nullptr) {}
void insert(int value);
Node *head;
Node *tail;
};
Node::Node(int val) :
value(val), next(nullptr), prev(nullptr)
{
}
void List::insert(int value) {
Node *tmp = new Node(value);
if(head == nullptr) {
head = tmp;
tail = tmp;
return;
}
Node *pos; // find the node greater or equal to 'value'
for(pos = head; pos && pos->value < value; pos = pos->next)
;
if(pos) { // appropriate pos found - insert before
tmp->next = pos;
tmp->prev = pos->prev;
tmp->next->prev = tmp;
if(tmp->prev) // there is some predecessor
tmp->prev->next = tmp;
else
head = tmp; // making a new first node
} else { // pos not found - append at the end
tmp->next = nullptr;
tmp->prev = tail;
tail->next = tmp;
tail = tmp;
}
}
You want to do two things: find position in list where new node belongs AND insert new node at a position. So, write two functions, one to do each task. Then you can test and debug them separately before integrating. This will be much more straight forward. Further reccomendation: write unit tests for each function, before implementing the functions.
/** Find node with largest value less than given
Assumes sorted list exist. If empty, throws exception
*/
Node & FindLessThan( int value );
/** Inset new node after given with value */
InsertAfter( Node& n, int value );
It will also be handy to have a function to insert the first node, if the list is empty,
/** Insert first node with value
#return true if list empty */
bool InsertFirstNode( int value );
The point is that you should hide all the pointer twiddling in functions that can be tested, so you can write a comprehensible mainline that will work first time:
if( ! InsertFirstNode( value ) )
InsertAfter( FindLessThan( value ), value );
Since you are using C++, make your list a class and the functions members.
Implementation details: You have to worry about special cases: new value goes before head or after tail. So I suggest using an enumeration to handle these.
/** Special cases for placing a new node */
enum class eFind
{
list_empty, // the list was empty
before_first, // the new node goes before the first node in list
before_node, // the new node goes before the specified node
after_last, // the new node goes after the last node in the list
};
/** Find node with smallest value greater than given
#param[out] place eFind enumeration, one of list_empty,before_first,before_node,after_last
#param[in] value being inserted
#return n node before which value should be placed
Assumes sorted list exist.
*/
Node * FindSmallestGreaterThan( eFind & place, int value )
It also turns out to be slightly easier ( less code ) to do an InsertBefore rather than InsertAfter. You can see the code running at cpp.sh/4xitp or the github gist
1. You can't initialize members inside a structure :
struct List
{
Node *head;
Node *tail;
};
2.(a) Prototypes of functions insertIt and insertNode are wrong.You are passing head and tail using pass by reference.It should be as follows :
void insertIt(Node * head ,Node * tail ,int value)
void insertNode(Node * head,Node * tail,int value)
2.(b) When you create a node in else part you should set the next and prev pointers of your new node to NULL :
tmp->prev=NULL;
tmp->next=NULL;
2.(c) As you have passed tail using pass by reference whatever changes you make inside while loop on tail are reflected in program.Hence use temporary pointer of type Node.
3. Also the design you are using is not good.Hence I would advice you to change it.This is my implementation of linked list :
main()
{
struct List Q;
Initialize_list(&Q);
Insert_it(&Q,12);
}
void Initialize_list(struct List *L)
{
L->head=NULL;
L->tail=NULL;
}
The problem is the check value < tail->prev->value in the while loop head. This does not check that tail->prev != nullptr is true. This is a problem for the case that head == tail and value < head->value. If head != tail, your code would indeed work, because the first time value < tail->prev->value is evaluated, tail->prev != nullptr is true and the case head->next == tail would be caught by the code in the loop body.
The correct check would be tail->prev != nullptr && value < tail->prev->value. This first checks that tail->prev can be derefenced.
Then you may end with tail->prev == nullptr after finishing the while loop (due to the new condition). The check for that can be moved out of the loop, leading to the following code:
while (tail->prev != nullptr && value < tail->prev->value) {
tail = tail->prev;
}
if (tail->prev == nullptr) {
// Prepend node to the list
return;
}
// Insert node in front of tail
EDIT: You can still check the condition tail->prev == nullptr within the loop; the check after the loop would then only be useful to catch the case head == tail && value < head->value. Not doing the check in the loop has the benefit of a shorter and (in my opinion) mode readable code.
This might be the code you're looking for ;-) You can run it as-is in VS2013. It simplifies your insert function to just a few if-statements. And that can be further simplified with use of terminal elements for head & tail.
I hope this helps :-)
struct Node
{
int value; Node *prev, *next;
};
struct DoublyLinkedSortedList
{
Node *head = nullptr, *tail = nullptr;
void insert(int value)
{
// Find first node bigger then the new element, or get to the end of the list
Node* node = head;
while (node && node->value <= value) { node = node->next; }
// Once found, insert your new element before the currently pointed node, or at the end of the list
node = new Node{ value, node?node->prev:tail, node };
if (node->prev) node->prev->next = node; else head = node;
if (node->next) node->next->prev = node; else tail = node;
}
};
#include <climits>
#include <iostream>
using namespace std;
int main()
{
cout << "This is a DoublyLinkedList test." << endl << endl;
// test the list
DoublyLinkedSortedList list;
list.insert(234);
list.insert(INT_MIN);
list.insert(17);
list.insert(1);
list.insert(INT_MAX);
list.insert(-34);
list.insert(3);
list.insert(INT_MAX);
list.insert(INT_MIN);
list.insert(9);
list.insert(7);
// print nodes in order;
cout << "This are the contents of the linked list front to back" << endl << endl;
for (Node* curr = list.head; curr != nullptr; curr = curr->next) { cout << curr->value << "; "; }
cout << endl << endl << "This are the contents of the linked list back to front" << endl << endl;
for (Node* curr = list.tail; curr != nullptr; curr = curr->prev) { cout << curr->value << "; "; }
cout << endl << endl;
system("pause");
}
I don't have much so far but I am trying to get the hang of using linked lists.
Struct:
struct Node
{
int value;
Node *next;
};
How can I add a node to the end of the list? I am just trying to take in a pointer for the head of a list and an int value to add in as a new node. When I try running what I have currently I get an exception.
void addNode(Node* head, int x)
{
Node* temp = new Node;
temp->data = x;
temp->next = NULL;
if(!head)
{
head = temp;
return;
}
else
{
Node* last = head;
while(last->next)
last=last->next;
last->next = temp;
}
}
I haven't really begun to work on merging the two lists. I just know that I need to take in 2 linked lists (or pointers to the head of 2 linked lists?) and then run through the lists for all the nodes.
E.G: Linked list 1 has 3 nodes: 4, 10, 20.
Linked List 2 has 4 nodes: 2, 5, 15, 60.
The merge list function would results in a new linked list with 2,4,5,10,15,20,60 as the nodes.
EDIT: In my main, I am calling the addNode function like so:
Node *head = new Node;
insertAtEnd(head,20);
Is that correct or could that be the cause of the exception?
By doing this:
void addNode(Node* head, int x)
// here ---------^
and then later this:
head = temp; // here
you're simply modifying the local head pointer, which took on the address value passed from the caller. Since head is not an actual reference to a pointer (it's just a pointer), the result is the caller's pointer passed as head remains unaltered. You never append your allocated node to your list, leak memory, it becomes a sad day...
Pass the pointer by reference instead. Fixing that, then fixing the invalid data member, which should actually be value and a pointer-to-pointer for walking the list to find the end, the result could look something like this:
#include <iostream>
struct Node
{
int value;
Node *next;
};
void addNode(Node*& head, int x)
{
Node **pp = &head;
while (*pp)
pp = &(*pp)->next;
*pp = new Node;
(*pp)->value = x;
(*pp)->next = nullptr;
}
void printList(const Node *head)
{
for (; head; head = head->next)
std::cout << head->value << ' ';
std::cout << '\n';
}
void freeList(Node *&head)
{
while (head)
{
Node *p = head;
head = p->next;
delete p;
}
}
int main()
{
Node *head = nullptr;
for (int i=1; i<=5; ++i)
addNode(head, i);
printList(head);
freeList(head);
}
Output
1 2 3 4 5
I leave the task of implementing an actual merge to you, but this should be enough to get you a manageable list up and running.
Update: From the OP's edited question:
Node *head = new Node;
insertAtEnd(head,20);
Apart from now-being a completely different named function, your node is default-initialized. In your case that means the resulting Node from new Node; has indeterminate values for both value and next. You're then passing that to your function, which assumes a determinate value (null) to terminate your loop.
This can be fixed any number of ways; the mechanics of the code above is one such way. There is no need to pre-allocate a head node in the first place if the list management code is of the understanding that NULL means no-list. Your addNode original post seemed to at-least-try to follow that mantra.
Declare the function the following way
void addNode( Node* &head, int x) ;
And instead of this code snippet
Node *head = new Node;
insertAtEnd(head,20);
You have to call the function the first time the following way
Node *head = nullptr; // or NULL
addNode(head,20);
Notice that there is no function with name insertAtEnd in your post. There is function addNode.:)
If you need to merge two lists then you can use this demonstrative program as a sample. Of course you will need to add some other functions as for example deleting lists that to get a complete project.
#include <iostream>
struct Node
{
int value;
Node *next;
};
Node * insert( Node *current, int value )
{
Node *tmp;
if ( current == nullptr )
{
tmp = new Node { value, nullptr };
}
else
{
tmp = new Node { value, current->next };
current->next = tmp;
}
return tmp;
}
std::ostream & display( Node *head,
std::ostream &os = std::cout,
const char *delimiter = " " )
{
for ( ; head; head = head->next ) os << head->value << delimiter;
return os;
}
Node * merge( Node * &head1, Node * &head2 )
{
Node *new_head = nullptr;
Node *current = nullptr;
while ( head1 != nullptr && head2 != nullptr )
{
Node *tmp;
if ( head2->value < head1->value )
{
tmp = head2;
head2 = head2->next;
}
else
{
tmp = head1;
head1 = head1->next;
}
tmp->next = nullptr;
if ( new_head == nullptr )
{
new_head = tmp;
current = new_head;
}
else
{
current->next = tmp;
current = current->next;
}
}
if ( head1 != nullptr ) new_head == nullptr ? new_head : current->next = head1;
if ( head2 != nullptr ) new_head == nullptr ? new_head : current->next = head2;
head2 = nullptr;
head1 = new_head;
return new_head;
}
int main()
{
Node *list1 = nullptr;
Node *list2 = nullptr;
list1 = insert( list1, 4 );
insert( insert( list1, 10 ), 20 );
display( list1, std::cout << "List1: " ) << std::endl;
list2 = insert( list2, 2 );
insert( insert( insert( list2, 5 ), 15 ), 60 );
display( list2, std::cout << "List2: " ) << std::endl;
std::cout << std::endl;
merge( list1, list2 );
display( list1, std::cout << "List1: " ) << std::endl;
display( list2, std::cout << "List2: " ) << std::endl;
return 0;
}
The program output is
List1: 4 10 20
List2: 2 5 15 60
List1: 2 4 5 10 15 20 60
List2:
this may be a cause of exception:
struct Node
{
int value; <----- Node structure has value property
Node *next;
};
Node* temp = new Node;
temp->data = x; <------ Assigning to data property of Node which does not exists
temp->next = NULL;
To add list you may use same approach
void addNode(Node* head, Node* head2)
{
Node* last = head;
while(last->next) last=last->next;
last->next = head2;
}
EDIT: In my main, I am calling the addNode function like so:
Node *head = new Node;
insertAtEnd(head,20);
This is wrong. You didn't initialize head->next, so within insertAtEnd the code while(last->next) last=last->next; will attempt to compare uninitialized pointer and if it isn't null, will dereference it. This will likely crash your program rather than throw an exception though. Then again, it's undefined behaviour, so anything may happen.
Since your insert function already covers the case of inserting to empty list, I would simply call
head = nullptr;
insertAtEnd(head,20)`;
Besides that, there's the bug of never updating the head pointer outside the function, which has already been covered in other answers.
I'm working with a single linked list and I want to sort it from lower to higher values of integer. I though I had the idea but then the execution enters in a infinite loop and I can't see clearly why. This is the part of the code I worked with:
class Node {
int data;
Node* next;
public:
Node() { };
void SetData(int aData) { data = aData; };
void SetNext(Node* aNext) { next = aNext; };
int Data() { return data; };
Node* Next() { return next; };
};
class List {
Node *head;
public:
List() { head = NULL; };
void Print();
void Append(int data);
void Delete(int data);
};
void List::Append(int data) {
// Create a new node
Node* newNode = new Node();
newNode->SetData(data);
newNode->SetNext(NULL);
// Create a temp pointer
Node *tmp = head;
if ( tmp != NULL ) {
// Nodes already present in the list
// Parse to end of list anytime the next data has lower value
while ( tmp->Next() != NULL && tmp->Next()->Data() <= newNode->Data() ) {
tmp = tmp->Next();
}
// Point the lower value node to the new node
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
}
else {
// First node in the list
head = newNode;
}
}
void List::Print() {
// Temp pointer
Node *tmp = head;
// No nodes
if ( tmp == NULL ) {
cout << "EMPTY" << endl;
return;
}
// One node in the list
if ( tmp->Next() == NULL ) {
cout << tmp->Data();
cout << " --> ";
cout << "NULL" << endl;
}
else {
// Parse and print the list
do {
cout << tmp->Data();
cout << " --> ";
tmp = tmp->Next();
}
while ( tmp != NULL );
cout << "NULL" << endl;
}
}
I'm confused if the list increases infinitely or the error comes from the Print function...
Sorry for the, perhaps, dummy errors.
Thanks.
Your problem is these two lines:
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
You should reverse them. Right now, you set tmp.next = newNode, and then newNode.next = tmp.next (= newNode), so newNode points to itself. Then traversing past newNode leads to an infinite loop.
You are failing to link two existing nodes properly. Look at this fragment of your code:
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
If for example you have this list:
head -> 5
and you want to insert a node with number 4 you will have:
head -> 5 <- tmp
newNode -> 4
With tmp->SetNext(newNode)
head (and tmp) -> 5 -> 4 <- newNode
With newNode->SetNext(tmp->Next());
head (and tmp) -> 5 -> 4 <- newNode
So any attempt to iterate through the list will result in and infinite loop:
5
4
4
4
4 ...... forever
// Point the lower value node to the new node
tmp->SetNext(newNode);
newNode->SetNext(tmp->Next());
Since you overwrite tmp->next in the first call, your second call is actually pointing newNode->next towards newNode itself, creating a cycle. This causes your infinite loop when calling Print ;-)
The solution is to do something like as follows...
Node* _next = tmp->Next();
tmp->SetNext(newNode);
newNode->SetNext(_next);
That being said, your code is still broken. The problems is that you don't check whether you need to place before the head of the list; try doing something as follows..
if ( tmp ) {
// Check whether to become new head
if ( tmp->Data() > newNode->Data() ) {
newNode->SetNext(tmp);
head = newNode;
}
else {
// Nodes already present in the list
// Parse to end of list anytime the next data has lower value
while ( tmp->Next() && tmp->Next()->Data() <= newNode->Data() ) {
tmp = tmp->Next();
}
// Point the lower value node to the new node
Node* _next = tmp->Next();
tmp->SetNext(newNode);
newNode->SetNext(_next);
}
}
else {
// First node in the list
head = newNode;
}
Side note: you can use an initializer list to rewrite code like...
List() : head(NULL) { };
In addition, if NULL is equivalent to 0, you can simplify conditions of the form X == NULL and X != NULL as merely X and !X, respectively.
See my ideone paste for the corrected version with an example.
int main() {
List l;
l.Append(15);
l.Append(40);
l.Append(7);
l.Print();
return 0;
}
... which produces
7 --> 15 --> 40 --> NULL