2 Linked list merge difficulties - c++

I am trying to merge two linked lists. One issue I have is how I can have my while loop continue to run even after 1 list reaches the end.
E.G: List1 values: 1, 3;
List 2 values: 2,6,7,8;
Ideally the output would be: 1,2,3,6,7,8
Currently my output is more like 1,2,3 (list1 has reached the end so the loop stops and the other list 2 values don't get added to the list).
Also, I would like for my merge to not be destructive to the original 2 lists that I merge, how can I accomplish this?
struct Node
{
int value;
Node *next;
};
void addNode(Node* &head, int x)
{
Node* temp = new Node;
temp->value = x;
temp->next = nullptr;
if(!head)
{
head = temp;
return;
}
else
{
Node* last = head;
while(last->next)
last=last->next;
last->next = temp;
}
}
void merge(Node * &head1, Node * &head2, Node * &head3)
{
while (head1 != nullptr && head2 != nullptr)
{
if (head1->value < head2->value)
{
addNode(head3, head1->value);
head1 = head1->next;
}
else
{
addNode(head3, head2->value);
head2 = head2->next;
}
}
}
Main function:
int main()
{
Node *head = nullptr;
Node *head2 = nullptr;
Node *head3 = nullptr;
for (int i=0; i<=8; i+=2)
addNode(head, i);
for (int i=1; i<=5; i++)
addNode(head2, i);
merge(head, head2, head3);
printList(head);
printList(head2);
printList(head3);
system("PAUSE");
return 0;
}

Nikos M. answered your first question, his answer is fine, so I won't repeat it. This answer addresses your second question:
Also, I would like for my merge to not be destructive to the original 2 lists that I merge, how can I accomplish this?
The answer is simple: Don't pass head1 and head2 by reference:
void merge(Node * head1, Node * head2, Node * &head3)
In fact, I would recommend making head1 and head2 const pointers:
void merge(const Node * head1, const Node * head2, Node * &head3)

The while loop exits as soon as either head1 or head2 becomes null. I think you want to add an extra piece of code to just append all remaining elements from the non-empty list (Im assuming they're already sorted).
Node* lastElements = list1 != nullptr ? list1 : list2;
while( lastElements != nullptr )
{
addNode(list3, lastElements->value);
lastElements = lastElements->next;
}
Add a constructor to Node so that next is always initialised to nullptr. I originally read code wrong an thought you'd missed this initialisation but adding a constructor will simplify your code and mean you wont forget to initialise next pointer if you create nodes elsewhere.
Node( int initValue)
: value(initValue)
, next(nullptr)
{}
and the start of your addNode function becomes 1 line instead of 3.
Node* temp = new Node(x);
Dont pass in reference to head1 and head2 pointers if the merge is not to be destructive. So something like this.
void merge( const Node* head1, const Node* head2, Node3*& outHead3)
{
//copy pointers in order to iterate through list
Node* current1 = head1;
Node* current2 = head2;
while( current1 != nullptr && current2 != nullptr)
{
//as before with relevant name changes
.
.
.
}
Node* lastElements = current1 != nullptr ? current1 : current2;
while( lastElements != nullptr )
{
addNode(outHead3, lastElements->value);
lastElements = lastElements->next;
}
}

you forget to merge any remaining items, use this:
// dont pass head1, head2 by reference in method call
void merge(Node * head1, Node * head2, Node * &head3)
{
// and/or use other variables to avoid changing head1, head2
Node * list1 = head1;
Node * list2 = head2;
while (list1 != nullptr && list2 != nullptr)
{
if (list1->value < list2->value)
{
addNode(head3, list1->value);
list1 = list1->next;
}
else
{
addNode(head3, list2->value);
list2 = list2->next;
}
}
// merge any remaining list1 items
while (list1 != nullptr)
{
addNode(head3, list1->value);
list1 = list1->next;
}
// merge any remaining list2 items
while (list2 != nullptr)
{
addNode(head3, list2->value);
list2 = list2->next;
}
}

Related

Can I use a while or for loop to print the list?

#include <iostream>
#include <string.h>
namespace forward_circular_linked_list {
typedef struct Node {
std::string data;
Node *nextNode;
}Node;
class ForwardCircularLinkedList {
private:
Node *head;
public:
ForwardCircularLinkedList() : head(nullptr) {}
void AddItem(std::string data) {
Node * newNode = new Node();
newNode->data = data;
if(head == nullptr)
{
head = newNode;
newNode->nextNode = head;
} else{
Node * copyOfHead = head;
while(copyOfHead->nextNode != head)
{
copyOfHead = copyOfHead->nextNode;
}
copyOfHead->nextNode = newNode;// process last node
newNode->nextNode = head;
}
}
void print()
{
Node * copyOfHead = head;
do
{
std::cout<<copyOfHead->data;
copyOfHead = copyOfHead->nextNode;
}while(copyOfHead != head);
}
public:
static void Test() {
ForwardCircularLinkedList list;
list.AddItem("Hello");
list.AddItem(" ");
list.AddItem("World");
list.AddItem("!");
list.print();
}
};
}
here, a do-while is being used to print the elements of the list.
At the current setup, Can I use a while or for loop to print the list?
Note: I am considering do-while and while as different looping structures.
Yes, you can use do-while or a for loop.
But do-while is more natural because it checks the condition after the body of code.
You have a circular data structure and (presumably) you want to print each element once.
Doing only one round of circling.
do{...move circulator}while(compare with head) has the right logic.
CGAL implements "circulators" and does exactly that, it starts from "head" does something and increments the circulator until it is head once again.
See https://doc.cgal.org/latest/Circulator/classCirculator.html (scroll to Example).
Note the example also checks for emptyness at start, but probably you want.
(In my mind a circular buffer is never empty, but I accept other opinions.)
With while you have:
Node * copyOfHead = head;
do
{
std::cout<<copyOfHead->data;
copyOfHead = copyOfHead->nextNode;
}while(copyOfHead != head);
With for you can have
Node * copyOfHead = head;
for(;;){
std::cout<<copyOfHead->data;
copyOfHead = copyOfHead->nextNode;
if(copyOfHead == head) break;
}
or
for(Node * copyOfHead = head;;){
std::cout<<copyOfHead->data;
copyOfHead = copyOfHead->nextNode;
if(copyOfHead == head) break;
}
or
for(Node * copyOfHead = head; ; copyOfHead = copyOfHead->nextNode){
std::cout<<copyOfHead->data;
if(copyOfHead->nextNode == head) break;
}
or (exploiting that the body of the loop evaluates to bool:true)
for(
Node * copyOfHead = head;
std::cout<<copyOfHead->data;
copyOfHead = copyOfHead->nextNode
) if(copyOfHead->nextNode == head) break;
The main advantage of for is the initialization, but still it is not worth it.
You can of course do the step outside the loop but then you have repeated code, etc.
(NOT RECOMMENDED, it may even have a bug)
Node * copyOfHead = head;
std::cout<<copyOfHead->data;
copyOfHead = copyOfHead->nextNode;
for(; copyOfHead != head ;copyOfHead = copyOfHead->nextNode){
std::cout<<copyOfHead->data;
}
So, there you have, do-while is exactly what you want for this kind of data structure! and for (or while-only) is exactly what you don't want.

While loop stops despite conditions being true

I'm merging 2 sorted linked list into one sorted list. My code gets everything except for the last output.
class Solution {
private:
ListNode* head = NULL;
ListNode* current1 = NULL;
ListNode* current2 = NULL;
ListNode* current3 = NULL;
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
setPointers(l1,l2); // set current pointers to beginning of each list
while((current1) && (current2)) {
if((current1->val <= current2->val) || (current2 == NULL)) {
ListNode* newNode = new ListNode;
newNode->val = current1->val;
current1 = current1->next;
if(isEmpty(head)) {
head = newNode;
current3 = newNode;
}
else {
current3->next = newNode;
current3 = current3->next;
}
}
else if((current2->val <= current1->val) || (current1 == NULL)) {
ListNode* newNode = new ListNode;
newNode->val = current2->val;
current2 = current2->next;
if(isEmpty(head)) {
head = newNode;
current3 = newNode;
}
else {
current3->next = newNode;
current3 = current3->next;
}
}
}
return head;
}
bool isEmpty(ListNode* head) {
if(head == NULL)
return true;
return false;
}
void setPointers(ListNode* list1, ListNode* list2) {
current1 = list1;
current2 = list2;
}
};`
Your input [1,2,4] [1,3,4] Output [1,1,2,3,4] Expected [1,1,2,3,4,4]
I thought the while loop keeps going until both current1 and current2 are both NULL but it seems to stop before making the last comparison.
The && operator evaluates to true only if both operands are true (i.e. not null in your case). Once at least one of the operands is false, then the loop stops.
You probably wanted while (current1 || current2), which will loop while at least one operand is not null.
edit:
also, be careful on the order of evaluation:
if((current1->val <= current2->val) || (current2 == NULL))
you are accessing current2 before checking whether it is not null (&& and || conditions are evaluated from the left, short-circuiting when the result is obvious from the value of the first operand).
You cannot be sure that current1 in the above condition is not null either.
This is not a direct answer to your question, but rather a comment, which I can't fit into the comments section. Why is your code so complicated? Merging two list is a very simple operation - and so should be your code:
Node* merge(Node* list1, Node* list2) {
Node* head = nullptr;
auto tail = &head;
while (list1 && list2) {
auto& list = (list2->value < list1->value) ? list2 : list1;
*tail = std::exchange(list, list->next);
tail = &(*tail)->next;
}
if (list1)
*tail = list1;
else if (list2)
*tail = list2;
return head;
}
The simpler your code is, the less is the chance to make an error.
Demo

Reversing a linked list starting from the tail using recursion

I still struggle with the recursion technique to solve the problem. I know there are nicer ways to solve my problem below of reversing a linked list. Most of the ways that I have seen, start to reverse the pointers by going from the head to the tail, either by using iteration or recursion.
I am trying for interest to reverse the list by first finding the last node in the list recursively and then changing the pointers everytime the function returns.
What am I doing wrong below exactly? Or will this method even work , without the need to pass more parameters to the recursive function? Thanks in advance for your help.
struct Node
{
int data;
struct Node *next;
};
Node* Reverse(Node *head)
{
static Node* firstNode = head;
// if no list return head
if (head == NULL)
{
return head;
}
Node* prev = NULL;
Node* cur = head;
// reached last node in the list, return head
if (cur->next == NULL)
{
head = cur;
return head;
}
prev = cur;
cur = cur->next;
Reverse(cur)->next = prev;
if (cur == firstNode)
{
cur->next = NULL;
return head;
}
return cur;
}
EDIT : Another attempt
Node* ReverseFromTail(Node* prev, Node* cur, Node** head);
Node* ReverseInit(Node** head)
{
Node* newHead = ReverseFromTail(*head, *head, head);
return newHead;
}
Node* ReverseFromTail(Node* prev, Node* cur, Node** head)
{
static int counter = 0;
counter++;
// If not a valid list, return head
if (head == NULL)
{
return *head;
}
// Reached end of list, start reversing pointers
if (cur->next == NULL)
{
*head = cur;
return cur;
}
Node* retNode = ReverseFromTail(cur, cur->next, head);
retNode->next = cur;
// Just to force termination of recursion when it should. Not a permanent solution
if (counter == 3)
{
cur->next = NULL;
return *head;
}
return retNode;
}
Finally Solved it :
Node* NewestReverseInit(Node* head)
{
// Invalid List, return
if (!head)
{
return head;
}
Node* headNode = NewestReverse(head, head, &head);
return headNode;
}
Node* NewestReverse(Node *cur, Node* prev, Node** head)
{
// reached last node in the list, set new head and return
if (cur->next == NULL)
{
*head = cur;
return cur;
}
NewestReverse(cur->next, cur, head)->next = cur;
// Returned to the first node where cur = prev from initial call
if (cur == prev)
{
cur->next = NULL;
return *head;
}
return cur;
}
I will not give you the code, I will give you the idea. You can implement the idea in the code.
The key to all recursion problems is to figure out two cases: repetition step and end case. Once you do this, it works almost as if magically.
Applying this principle to reversing a linked list:
End case: the list of one element is already reversed (this is straightforward) and returning the element itself
Repetition case: Given list L, reversing this least means reversing an L', where L' is the L' is the list without the very first element (usually called head), and than adding the head as the last element of the list. Return value would be the same as a return value of the recursive call you just made.
It can be done. The key in understanding recursion is What is the starting point?
Usually I create a "starting" function which prepares the first call. Sometimes it is a separate function (like in non OO implemnatation at bottom). Sometimes it's just a special first call (like in example below).
Also the key is in remembering variables before they change and what is the new head.
The new head is the last element of the list. So You have to get it up from the bottom of the list.
The nextelement is always your parent.
Then the trick is to do everything in the correct order.
Node* Reverse( Node* parent) // Member function of Node.
{
Node* new_head = next ? next->Reverse( this )
: this;
next = parent;
return new_head;
}
You call the function with: var.Reverse( nullptr);
Example:
int main()
{
Node d{ 4, nullptr };
Node c{ 3, &d };
Node b{ 2, &c };
Node a{ 1, &b };
Node* reversed = a.Reverse( nullptr );
}
So what is happening here?
First we create a linked list:
a->b->c->d->nullptr
Then the function calls:
a.Reverse(nullptr) is called.
This calls the Reverse on the next node b.Reverse with parent a.
This calls the Reverse on the next node c.Reverse with parent b.
This calls the Reverse on the next node d.Reverse with parent c.
d doesn't have next node so it says that the new head is itself.
d's next is now it's parent c
d returns itself as the new_head.
Back to c: new_head returned from d is d
c's next is now it's parent b
c returns the new_head it recieved from d
Back to b: new_head returned from c is d
b's next is now it's parent a
b returns the new_head it recieved from c
Back to a: new_head returned from b is d
a's next is now it's parent nullptr
a returns the new_head it recieved from b
d is returned
Non object oriented implementation;
Node* reverse_impl(Node* parent)
{
Node* curr = parent->next;
Node* next = curr->next;
Node* new_head = next ? reverse_impl( curr )
: curr;
curr->next = parent;
return new_head;
}
Node* reverse(Node* start)
{
if ( !start )
return nullptr;
Node* new_head = reverse_impl( start );
start->next = nullptr;
return new_head;
}
Here's a full implementation I wrote in 5 minutes:
#include <stdio.h>
struct Node
{
int data;
struct Node *next;
};
struct Node* Reverse(struct Node *n)
{
static struct Node *first = NULL;
if(first == NULL)
first = n;
// reached last node in the list
if (n->next == NULL)
return n;
Reverse(n->next)->next = n;
if(n == first)
{
n->next = NULL;
first = NULL;
}
return n;
}
void linked_list_walk(struct Node* n)
{
printf("%d", n->data);
if(n->next)
linked_list_walk(n->next);
else
printf("\n");
}
int main()
{
struct Node n[10];
int i;
for(i=0;i<10;i++)
{
n[i].data = i;
n[i].next = n + i + 1;
}
n[9].next = NULL;
linked_list_walk(n);
Reverse(n);
linked_list_walk(n+9);
}
Output:
0123456789
9876543210

Merging 2 linked lists and appending to the end of linked lists c++

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.

reverse order of linked list by push

i am trying to make a function that changes the order of the pointers of the nodes so that the original list is reversed.
my solution is based on iterating over the main list, then reversing the order of each 2 adjacent nodes: (n1)->(n2) would be (n1)<-(n2) after the first iteration.
my try:
Node push1(Node* curr) {
if(curr == NULL || *curr == NULL) {
return NULL;
}
Node temp = (*curr)->next;
if(temp == NULL) {
return NULL;
}
(*curr)->next = *curr;
return temp;
}
/*******************************/
void reverse2(Node* head) {
Node curr = *head;
while(curr != NULL) {
curr = push1(&curr);
}
}
PROBLEM: i ran through an infinity loop. i tried to fix that but then the list didn't reverse order. is there a way using this approach of push1() that could work?
NOTE: i am not seeking the solution with 3 pointers or recursion.
This works, but is a bit silly
Node* push1(Node** prev, Node* curr)
{
Node* ret = curr->next;
curr->next = *prev;
(*prev)=curr;
return ret;
}
void reverse2(Node** head)
{
Node* prev = *head;
if(!prev) return;
Node* curr = prev->next;
if(!curr) return;
prev->next = 0;
while(curr)
{
curr = push1(&prev,curr);
}
*head = prev;
}
This is not readable or portable but it does not use recursion or additional variables:
struct list {
list *next;
/* ... */
};
list *
reverse(list *l)
{
list *head = nullptr;
while (l) {
head = (list *) ((uint64_t) head ^ (uint64_t) l->next);
l->next = (list *) ((uint64_t) l->next ^ (uint64_t) head);
head = (list *) ((uint64_t) head ^ (uint64_t) l->next);
l = (list *) ((uint64_t) l ^ (uint64_t) head);
head = (list *) ((uint64_t) head ^ (uint64_t) l);
l = (list *) ((uint64_t) l ^ (uint64_t) head);
}
return head;
}
The trick is to use xor swaps.
This is fairly easy using a std::stack<> data structure in combination with a std::vector<>. Recall that Stacks are a type of container, designed to operate in a LIFO context (last-in first-out), where the elements are inserted and extracted only from one end of the container.
So in your situation you will create a stack, add your nodes to the stack in the order you already have, then popping them back off the stack reverses the order of the nodes.
I have sketched the code to do this but note that it is not tested, you should be able to adapt this idea to you situation:
#include <stack>
#include <vector>
std::vector<Node> reverseNodes(Node* currNode, Node* startNode) {
std::vector<Node> reversed;
std::stack<Node> nodeStack;
// First add nodes to the stack:
for (Node* aNode = currNode; aNode != startNode; aNode = aNode->next) {
nodeStack.push(aNode);
}
// Next add your starting node to the stack (last-in):
nodeStack.push(startNode);
// Popping off of the stack reverses the order:
while (!nodeStack.empty()) {
reversed.push_back(nodeStack.pop());
}
// Return the nodes ordered from last->first:
return reversed;
}