Currently I have the following function to merge two sorted linked lists of type mylist. At the moment, there are some bugs that I have not been able to pinpoint and fix so far. What the function is basically supposed to do is, lets say A = 1 2 3 and B = 3 4 5. Then when I merge both (assuming both lists are sorted), A will become 1 2 3 3 4 5 and B will become null.
At the moment, for example when I try, A = 1 2 3 and B = 4 5 6 and merge both, A becomes 6 and B becomes 4. I know there are problems with the algorithm but I've not been able to pinpoint and fix yet. I'm new to programming. Any help will be appreciated!
void mylist::merge(mylist& b)
{
if (!this->isSorted() || !b.isSorted())
cout << "error" << endl;
Node* ptr1 = b.head;
Node* prev_a = NULL;
Node* curr_a = head;
Node* curr_b = ptr1;
while (curr_b) {
if (curr_a && head < ptr1) {
prev_a=curr_a;
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b; // curr_b is first element in 'a'
if (curr_a) {
prev_a = curr_a;
curr_a = curr_a->next;
}
curr_b = b_next;
}
}
return;
}
EDIT:
I have made the following changes as mentioned but I still get A = 6 and B = 4 after merging A = 1 2 3 & B = 4 5 6.
void mylist::merge(mylist& b)
{
if (!this->isSorted() || !b.isSorted())
cout << "error" << endl;
Node* ptr1 = b.head;
Node* prev_a = NULL;
Node* curr_a = head;
Node* curr_b = ptr1;
while (curr_b) {
if (curr_a && head->key < ptr1->key) {
prev_a=curr_a;
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b; // curr_b is first element in 'a'
prev_a = curr_a;
curr_b = b_next;
}
return;
}
1) Sorting problem:
in your instruction
if (curr_a && head < ptr1) { // argh !!!
you compare two pointers to Node (i.e. their addresses) and not the value pointed to.
2) Extreme case (that applies to your test data):
If first element of list b is greater than any elements of list a (supposing that you've corrected problem #1), then you will loop until curr_a is null, without ever having set prev_a. You would then insert the elements of b at the head of a (in the reverse order)
3) First merge in the middle of list a:
In a normal merge, you could cycle through list a until you have the first element of list b which is smaller than the element of a. prev_ais still not set at this moment. So you'll connect the next-element of current-element of b to the current element of a (which is ok), but then, as prev_a is NULL, you'll connect the head of a to the current element of b, thus LOOSING the whole chain of elements in a that were before the current one.
Steps to the solution:
If it's for an assignment given by your teacher:
while (curr_b) {
if (curr_a && curr_a->key < curr_b->key) { // assuming data is stored in the node and has a comparator defined
prev_a = curr_a; // keep track of it (WAS MISSING)
curr_a = curr_a->next;
}
else {
Node* b_next = curr_b->next;
curr_b->next = curr_a;
if (prev_a) prev_a->next = curr_b;
else head = curr_b;
prev_a = curr_b; // THE ELEMENT you've inserted is now prev_a
// curr_a SHALL not change since the next element of b can also be smaller than it
curr_b = b_next;
}
}
If it's for real code, you should really consider standard <list> container and its existing merge() function ;-)
EDIT: I've just realised that there was another issue and updated also the else part in the loop above. And I realized I was so focused on the key comparison, that I didn't notcie the wrong pointers were used, so that it didn't succeed in all the test cases !
The comparison 'head < ptr1' is meaningless. Those are pointers, not values.
ptr1 seems redundant with curr_b
You seem to start by looking for the tail of A. Why not make that a function in its own right?
Continuing with that divide and conquer approach, I'd make functions that test if a list is empty, pop the head off a list returning what it popped, and a function that appends something to the end. Then your final answer is:
mylist::merge(mylist &b) {
while (!b.empty())
push_back(b.pop_front());
}
Related
Im trying out a leetcode question 328. Odd even linked list.
We are required to rearrange the below list to put all the odd nodes together and them the even nodes together. For example:
1->7->3->2->4
And then need to rearrange them to link the odd placed with the odd and then add the even at the end
1 3 4 7 2
However my issue is, when dealing with a list of even number of nodes, it leaves the last even number at the end of the odd numbers
For instance
5 7 4 3 9 8 2 1
and my code rearranges it to
5 4 9 2 1 7 3 8
but the answer should be
5 4 9 2 7 3 8 1
How can i fix the code for it to consider the last even number as an even number instead of odd?
if (head->next == NULL || head->next->next == NULL)
return head;
ListNode *odd = head;
ListNode *even = head->next;
ListNode *evenHead = even;
while (even != NULL && even->next != NULL){
odd->next = even->next;
odd = odd->next;
even->next = odd->next;
even = even->next;
}
odd->next = evenHead;
return head;
}
Looks good! Almost there!
This'd pass:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
static const struct Solution {
ListNode* oddEvenList(ListNode* head) {
if (!head) {
return head;
}
ListNode* odd = head;
ListNode* even_head = head->next;
ListNode* even = even_head;
while (even && even->next) {
odd->next = odd->next->next;
even->next = even->next->next;
odd = odd->next;
even = even->next;
}
odd->next = even_head;
return head;
}
};
c++ variable naming is usually snake_case. It's OK to consistently use other styles though.
Structure
SinglyLinkedListNode {
int data;
SinglyLinkedListNode* next;
};
Function
bool has_cycle(SinglyLinkedListNode* head) {
SinglyLinkedListNode* s=head,*f=head->next;
while(s != NULL && f != NULL && f->next != NULL)
{
s = s->next;
f = f->next->next;
if(s->data == f->data)
return true;
}
return false;
}
According to the algorithm, if the slow pointer s and fast pointer f arrive on the same node the list is said to have a cycle. I'm assuming the same node will have the same data but then why am I getting failed test cases?
When I change (s->data = f->data) to (s == f) it works fine.
What is the difference between s == f and s->data == f->data?
The main issue here is your final checking condition. This will fail in a test case where there can be duplicates present (in the loop). When you are checking for the "same node" checking if the pointer value is same is better because it will always be unique, i.e., every node has an unique address but it is not necessary for it to be true for the value the node contains. For example:
1 -> 3 ->4 ->5 -> 6 -> 4 -> 7 -> NULL
//Note giving relative indexing(0th, 1st, .. and random addressing for understanding)
Iter 1: s is at 1(0th node, 1000010092) while f is at 3(1st node, 21983193)
Iter 2: s is at 3(1st node, 21983193) while f is at 5(3rd node, 129764714)
Iter 3: s is at 4(2nd node, 12984124) while f is at 4(5th node, 149284124)
See the ambiguity!!
Even though your algorithm is giving a TRUE a cycle doesn't exist.
But if you checked by the addressing, this false positive wouldn't have happened.
Tip: check if there are duplicates in any problem, they tend to be added to bring up such issues.
I'm having some trouble understanding the recursive part of binary search tree insertion.
bstnode* insert(bstnode* root,int data)
{
if(root==NULL){
bstnode* tmp= new bstnode();
tmp->data=data;
tmp->left=tmp->right=NULL;
return tmp;
}
if(data<root->data)
root->left = insert(root->left, data);
else
root->right = insert(root->right, data); //can't understand the logic here
return root;
}
/* consider following BST with their addresses[]:
15 [100]
/ \
10 20 [200]
\
tmp [300]
*/
According to me root->right = insert(root->right, data); should store the address of the newly created node in root->right so this code shouldn't work for tree with height>2.
However, it is working perfectly for any number of nodes.
I must be missing some crucial details here.
suppose I want to insert 25 in BST i.e. insert(root,25);
as 25>15:- I'm breaking down the recursive part here:
root->right = insert(root->right, 25);
or 15->right = insert(15->right,25); Here, recursively calling it again because 25>20
insert(root->right, 25) => root->right->right = insert(root->right->right, 25);
or insert(15->right, 25) => 20->right = insert(20->right, 25);
insert(20->right,25) is NULL so a new node tmp is created.
insert(20->right,25); returns tmp.
unwinding the recursion now.
//20->right = insert(20->right, 25);
so,
20->right= 300 (tmp address);
//insert(15->right, 25) => 20->right
//and 15->right = insert(15->right,25);
15->right = 20->next;
therefore 15->right = [300] address.
or
root->right = [300] address.
what's wrong with my approach?
Again an overview of recursive calls:
15->right = insert(15->right,25);
15->right = [20->right = insert(20->right,25)]; //20->right is NULL so creating new node
15->right = [20->right= 300 address of tmp];
15->right = [20->right or 300]
15->right = [300] // but in reality 15->right = [200]
you are forgetting that root->right is the root->right of the address you are passing into the function as root. every call to insert passes in root->right or root->left depending on which way you traverse.
This statement is incorrect:
root->right = root->right->right = tmp;
once an iteration of the function is returned it is removed from the stack so in this case we have 3 calls I will put your numbers in place of the pointer value.
insert(15->right,25)
insert(20->right,25)
the last one is null so it creates the node with 25 and returns it to the call insert(20->right,25) and sets 25 as 20->right so you have a tree that looks like this
/* consider following BST with their addresses[]:
20 [200]
\
25 [300]
*/
it then returns this tree to the call insert(15->right,25) and sets that trees right to the tree we just returned which so we get your final tree
/* consider following BST with their addresses[]:
15 [100]
/ \
30 20 [200]
\
25 [300]
*/
EDIT: let me see if I can clarify. Lets look at your tree again
/* consider following BST with their addresses[]:
15 [100]
/ \
10 20 [200]
\
tmp [300]
*/
we want to insert 25 so we call (again I will use the value at that node of the tree to represent the pointer we are passing)
insert(15, 25)
this then calls insert on root->right which happens to be 20
insert(20, 25)
this calls insert again on 20 right node now which happens to be null
insert(null,25)
so lets now look at the returns
insert(null,25) returns a node with 25 in it and then is remove from the stack
return 25;
insert(20,25) gets its return of a node with 25. it sets its right child to 25 which looks like this
20->right = 25;
return 20;
now we are back to the original call of insert(15,25). it got returned 20. so it does
15->right = 20;
return 15;
I think the confusion may be coming from two different sources for you.
First the tree commented into your code would not be possible. Second is that a new node is only created when the function is passed in a null pointer. Only values less than 15 can go to the left. It would be something like this instead (depending on add order):
15
/ \
20
/ \
30
When you go to add 25 to this it will end up as follows:
15
/ \
20
/ \
30
/
25
I will try and step through the code on this to explain. When adding 25 to the original tree on the first function call the first node is not NULL and 25 > 15 so the
else
{
root->right = insert(root->right, data);
}
is called. This calls the same insert function recursively but is now using the 20 node as it's comparison. Again not null and 25 > 20 so call insert on right node as above. This again calls the recursive function but now on 30. 25<30 so it calls the function on the left node. At this point the function as been passed in a NULL pointer as there is nothing there and a new node is created and placed in this spot.
Note that insert() always returns the root that was passed to it as an argument unless root == NULL. There's therefore no way for the new node you insert to "walk up the tree". What happens in the recursive call doesn't matter -- you always return the same root that you were passed in the non-NULL case.
Despite the way some people teach recursion, I think it helps (for my brain anyway) to not try to unroll the recursion, and instead consider whether the logic makes sense:
If you are passed a non-NULL node and data < root->data, would you get the correct result if you do root->left = insert(root->left, data) and assume the insert() magically "just works" (i.e., that it inserts data into the left tree and returns the root of that tree)?
If the logic checks out for both the left and right case, you then consider the base case: If you are passed a NULL node, will you return the correct one-element tree?
If the logic checks out for the base case too, then you know your code must be correct, since the recursive steps make sense and you know that you will land in a base case that also makes sense (since you will eventually reach a NULL node as you walk down the tree).
In a way you are correct. You can never have a sub-tree (not tree) of height >2.
In this code, you will never have a root->right->right because, as far as the code is concerned, when you call
root->left = insert(root->left, data);
the (local) root pointer is now pointing to the node you just inserted. the (local) root is pointing to root->left.
Therefore, you CAN have a tree of any height(However, the local root pointer is pointing to a sub-tree of height <2)
In a binary tree traversal algorithm like below cited from this question, why do we need to check the second condition
pre->right != current? is this a loop condition? when would this happen?
pre = current->left;
while(pre->right != NULL && pre->right != current)
pre = pre->right;
Because the latter code makes a cycle (i.e. child pointing to a parent):
pre->right = current;
The cycle is deleted later, however, but the pre->right != current test tris to avoid following the cycle endlessly.
Consider the tree given below,
A
/ \
B C
/ \ /\
D E F G
The node A which is the root is initialized as current. Now the code given by you tries to find out the immediate predecessor of A in inoreder traversal. As we know the inorder traversal of the given tree is as follows,
D B E A F C G
So the code identifies E as the immediate predecessor of A.
[Pertaining to your Question-code]
Assume tree:
A
/ \
B C
It's In-order traversal = B,A,C
Now consider, B was already printed by
if(current->left == NULL)
{
printf(" %d ", current->data);
current = current->right;
}
So, The Condition:
pre->right != current
is required to break while loop (which may be cyclic at times), exactly when our aim is to print node A.
In this case, at the end of the while loop i.e. while(pre->right != NULL && pre->right != current), we'll have :
1) pre pointing to left node B - which is already printed
2) current pointing to middle node A - Next to be print, thus breaking cycle link we've created just for this. Following part takes care of this:
else
{
pre->right = NULL; // Break cyclic link we've created for printing 'A'
printf(" %d ",current->data);// prints 'A'
current = current->right; // Now, Aim for 'C'
}
This is a piece of code that tries to build a linked list.
struct node {
char name[20];
int age;
int height;
node* next; // Pointer to the next node
};
node* startPTR = NULL;
void addNode_AT_END() {
node *temp1;
node *temp2;
temp1 = new node;
cout << "Enter the name : ";
cin >> temp1->name;
cout << endl << "Enter the age : ";
cin >> temp1->age;
cout << endl << "Enter height : ";
cin >> temp1->height;
temp1->next = NULL;
if( startPTR == NULL) {
startPTR = temp1;
} else {
temp2 = startPTR;
while( temp2->next != NULL )
temp2 = temp2->next;
temp2->next = temp1;
}
}
The following is diagram after 2 back to back calls to the above function.
start = addr1;
|
V
(addr1) ----> (addr2) ----> (NULL) at end
^
|
temp2
where addr1 and addr2 are the address of the first and second nodes respectively.
What happens after the third call ? How the iteration will go on for the third call? I am unable to understand how the list links up after the second call.According to me all that has been build up till know will vanish.Then how will list move further ? How is node placed during the third call?
Here is where all the magic happens:
1. temp2 = startPTR;
2. while( temp2->next != NULL )
3. temp2 = temp2->next;
4. temp2->next = temp1;
First, temp2 will point to the beginning of the list. In lines 2 and 3, you change temp2 to the next node until you reach the node where temp2->next is NULL. This node is the last node of the list, regardless of the size of the list.
Finally, in line 4 you change temp2->next to temp1 so now it points to the new node (that is last node now points to the new node). temp1->next is also NULL, so temp1 now represents the end of the list.
After line 1 you have
start = addr1;
|
V
(addr1) ----> (addr2) ----> (NULL)
^
|
temp2
temp2->next is not NULL (it is addr2), so you iterate and execute line 3 and you get:
start = addr1;
|
V
(addr1) ----> (addr2) ----> (NULL)
^
|
temp2
temp2->next is now NULL. So you stop the loop and execute line 4 and you get:
start = addr1;
|
V
(addr1) ----> (addr2) ----> (addr3) ----> (NULL)
^ ^
| |
temp2 temp1
Note: Do you know how pointers work? Imagine this: You have a node, which is some data in the memory. When you have variables in memory, these variables have addresses. Let's say addr1 is 10, addr2 is 150 and addr3 (which is the node just newed) is 60. start has value 10. Therefore, "pointing" to the first node of the list (that is using this address, you have access to its data). One of these data, is the next field. The first node's next field has value 150, thus pointing to the next node. When you say temp2 = start, you put number 10 in temp2, at this point temp2->next has value 150. When you say temp2=temp2->next, you simply put value 150 in temp2, overwriting the previous value. This way you have effectively moved your pointer from pointing to the first node, to now pointing to the second node. Now temp2->next is NULL (that is 0). When you now say temp2->next=temp1, you put value 60 in the next field of temp2. So now temp2->next is 60. temp2->next->next is NULL.
It's pretty simple. The while cycle will move temp2 to the last element. Then the node you created, pointed by temp1, is assigned as temp2's next node
I don't get what's bothering you. During any call while() loop will go through all the nodes in the list untill it reaches the end, and then set the pointer in the last one to the newly allocated node (temp1).
temp1 and temp2 are pointers. they do not store data of the node, they store address in memory where data is stored. so at the end of first iteration, after startPTR = temp1 startPTR points to the same address that temp1 pointed to. it doesn't matter if temp1 is still there, since now startPTR points to the node. at the end of the second call temp2->next=temp1 (temp2==startPTR at this moment) makes next field of the node point to the newly allocated temp1