I stumbled upon an algorithm problem of which I want an optimised approach.
Here goes,
Suppose I have a linked-list which is sorted. Each element of the linked list may have a down pointer which contains a List which is sorted too.
What is the best memory and time efficient way to merge such a list with the subsequent down list?
For eg,
1 -> 5 -> 10 -> 60 -> 100
| | |
20 50 101
| |
30 70
This should get converted to:
1 -> 5 -> 10 -> 20 -> 30 -> 50 -> 60 -> 70 -> 100 -> 101
Data structure for linked list:
Node {
Node next;
List down;
Integer value;
}
Thanks in advance :)
Here is the link to the solution :
https://www.geeksforgeeks.org/flattening-a-linked-list/
Just to give you a brief idea of the post on this link:
Start from leftmost node of list, and you need follow the merge step of Merge sort.
This merge will happen between right node(right of 1 which is 5) down list, and down list( down of 1 which is null) of leftmost node.
You need to create a new flattened list, and add to this list the nodes after comparison between 2 lists.
Keep on moving forward in your main list after merging 2 down lists.
The simplest and efficient enough would be scanning the whole 'main' list, unlinking each 'down list' and appending it to the main one, and finally natural-merge sorting the resulting list as a whole.
Idea:
Traverse through the original linked list and merge the linked lists of the elements accordingly.
This is a code written in c++, this is an iterative approach but you can also write similarly write the recursive approach which would, of course, look simple by no of lines, but not O(1). So, better use the iterative approach :
// same logic merging two sorted arrays
Node* merge(Node *head1, Node *head2) {
struct Node *end = NULL;
struct Node *start = NULL;
// merge till one of the linked list is completely traversed
while (head1 != 0 and head2 != 0) {
if (head1->data <= head2->data) {
if (end == NULL) {
start = head1;
end = start;
}
else {
end->bottom = head1;
end = end->bottom;
}
head1 = head1->bottom;
}
else {
if (end == NULL) {
start = head2;
end = head2;
}
else {
end->bottom = head2;
end = end->bottom;
}
head2 = head2->bottom;
}
}
// check for the remaining elements in linked list which was not traversed completely
if (head1 != NULL) {
end->bottom = head1;
}
else {
end->bottom = head2;;
}
return start;
}
Node *flatten(Node *root)
{
// base condition
if (root == NULL || root->next == NULL) {
return root;
}
// merge the linked list of elements accordingly
Node *prev = root, *to = root->next;
while (to != NULL) {
prev = merge(prev, to);
to = to->next;
}
return prev;
}
Related
In flatten function I can't understand recursion parts??
2.when flatten return root(not the if section), how root received here?
//below is the code of flatten() which start from end of node .each node have two pointers next and down . This function merge and sort all of them and return them.for help attach full code in last.
// Java program for flattening a Linked List
Node flatten(Node root) {
// Base Cases
if (root == null || root.right == null)
return root;
// recur for list on right
root.right = flatten(root.right);
// now merge
root = merge(root, root.right);
// return the root
// it will be in turn merged with its left
return root;
}
//full code for help
//flatten inked list full code
// debug in vs studio
class LinkedList {
Node head; // head of list
/* Linked list Node */
class Node {
int data;
Node right, down;
Node(int data) {
this.data = data;
right = null;
down = null;
}
}
// An utility function to merge two sorted linked lists
Node merge(Node a, Node b) {
// if first linked list is empty then second
// is the answer
if (a == null)
return b;
// if second linked list is empty then first
// is the result
if (b == null)
return a;
// compare the data members of the two linked lists
// and put the larger one in the result
Node result;
if (a.data < b.data) {
result = a;
result.down = merge(a.down, b);
}
else {
result = b;
result.down = merge(a, b.down);
}
result.right = null;
return result;
}
Node flatten(Node root) {
// Base Cases
if (root == null || root.right == null)
return root;
// recur for list on right
root.right = flatten(root.right);
// now merge
root = merge(root, root.right);
// return the root
// it will be in turn merged with its left
return root;
}
/*
* Utility function to insert a node at beginning of the
* linked list
*/
Node push(Node head_ref, int data) {
/*
* 1 & 2: Allocate the Node &
* Put in the data
*/
Node new_node = new Node(data);
/* 3. Make next of new Node as head */
new_node.down = head_ref;
/* 4. Move the head to point to new Node */
head_ref = new_node;
/* 5. return to link it back */
return head_ref;
}
void printList() {
Node temp = head;
while (temp != null) {
System.out.print(temp.data + " ");
temp = temp.down;
}
System.out.println();
}
// Driver's code
public static void main(String args[]) {
LinkedList L = new LinkedList();
L.head = L.push(L.head, 7);
L.head = L.push(L.head, 5);
L.head.right = L.push(L.head.right, 50);
L.head.right = L.push(L.head.right, 22);
L.head.right = L.push(L.head.right, 19);
L.head.right.right = L.push(L.head.right.right, 45);
L.head.right.right = L.push(L.head.right.right, 40);
L.head.right.right = L.push(L.head.right.right, 35);
L.head.right.right = L.push(L.head.right.right, 20);
// Function call
L.head = L.flatten(L.head);
L.printList();
}
If I understand correctly, you want to know how the recursion works in this code.
1 Node flatten(Node root) {
2 // Base Cases
3 if (root == null || root.right == null)
4 return root;
5
6 // recur for list on right
7 root.right = flatten(root.right);
8
9 // now merge
10 root = merge(root, root.right);
11
12 // return the root
13 // it will be in turn merged with its left
14 return root;
15 }
Let's say our linked list looks like this:
5 -> 10 -> 19 -> 28
| | | |
V V V V
7 20 22 35
| | |
V V V
8 50 40
| |
V V
30 45
Now, let's traverse this method line by line.
The base case ensures that once we reach the right most linked list, it is returned as is.
So, now since we passed the above-linked list to this function whose root is not null and has another linked list to its right, function control moves to line 7.
On line 7, flatten(root.right) function is called. Let us assume for our sanity, that this function does exactly what it is supposed to and it flattens all the linked lists to its right and we assign this newly flattened right portion of the linked list to root.right.
Now, all we are left with is our base linked list 5-7-8-30 and to its right the flattened linked list. So, we only have to merge these 2 now and return it back which we do in line 10 and 14.
If you, noticed above, I have avoided the hassle of going into the trouble of following the rabbit hole of thinking about function calls on Line 7. This simplifies the recursive logic.
We can think recursively as well and reach to same conclusion because for each subsequent flatten function call, the merge will happen and the root will be returned to the previous function call which will be assigned to root.right in parent function and then merged and returned to its parent function call and the same process will be followed until the control reaches the head of the linked list where only 2 linked lists will remain at the end which will be merged and returned back.
There is a 3rd way to understand this visually with the help of a function callstack diagram. I'll update this answer later to include that when I get some time.
I am having problems with merge sorting a linked list. For some reason, some of the nodes keep getting disconnected from the list. The main problem seems to be coming from multiple conditional jumps since lists such as 1 4 2 3 are sorted, albeit with 6 conditional jumps, while 4 2 3 1 loses all nodes except the one holding the value 4. My code is based off of the code from tutorialspoint.com.
class Node {
public:
int val;
Node *next;
};
class Linked_list {
private:
unsigned int length;
Node *head;
//desc: sorts in ascending order then merges two linked lists
//param: Node*, the lists being sorted
Node* Linked_List::merge_lists_ascend(Node* ll1, Node* ll2) { //function for merging two sorted list
Node* newhead = NULL;
if(ll1 == NULL)
return ll2;
if(ll2 == NULL)
return ll1;
//recursively merge the lists
if(ll1 -> val <= ll2 -> val) {
newhead = ll1;
newhead -> next = merge_lists_ascend(ll1->next,ll2);
}
else {
newhead = ll2;
newhead -> next = merge_lists_ascend(ll1,ll2->next);
}
return newhead;
}
//desc: splits a linked list into two lists
//param: Node*, the list being split; Node**, the two lists that will be filled
//by the split list
void Linked_List::splitList(Node* start, Node** ll1, Node** ll2) {
Node* slow = start;
Node* fast = start -> next;
while(fast != NULL) {
fast = fast -> next;
if(fast != NULL) {
slow = slow -> next;
fast = fast -> next;
}
}
*ll1 = start;
*ll2 = slow -> next;
//spliting
slow -> next = NULL;
}
//desc: recursive function that runs through the splitting, sorting and merging
//param: Node**, the starting node
Node* Linked_List::merge_sort_ascend(Node* start) {
Node* head = start;
Node* ll1;
Node* ll2;
//base case
if(head == NULL || head->next == NULL) {
return head;
}
splitList(head,&ll1,&ll2); //split the list in two halves
//sort left and right sublists
ll1 = merge_sort_ascend(ll1);
ll2 = merge_sort_ascend(ll2);
//merge two sorted list
start = merge_lists_ascend(ll1,ll2);
return start;
}
When you call merge_sort_ascend recursively, you ignore its return value. That return value is important.
I am looking at this challenge:
Given are numbers m and p, which both may be as large as 250000. The next m lines have one of the following commands:
APPEND y, which adds y to the end of our list (queue)
ROTATE, which reverses the p last elements of the list. If the list has fewer than p elements, it reverses all of the elements of the list.
Our job is to print the list after all commands have been executed.
A brute force approach is to reverse the array manually, which would have a complexity of O(pm), but you are required to implement it with a complexity of O(m).
I have thought about using a doubly linked list, and I am quite sure it would work, but I could not complete my answer.
Example
Input
8 3
APPEND 1
APPEND 2
APPEND 3
APPEND 4
ROTATE
APPEND 5
APPEND 6
ROTATE
Output
1 4 3 6 5 2
The idea of a doubly linked list is correct. To make it work you need to step away from prev/next notions, but just keep track of the potential 2 neighbours a node may have, without any indication of direction (prev/next).
Your doubly linked list will have a head and a tail -- that must stay. And you are right to also maintain a reference to the node that is currently the start node of the "k last elements" (or fewer when there are not that many elements in the list). Keep that updated whenever you add a node. In order to know in which direction to move that reference, also maintain a reference to the node that precedes it.
Then, when a reversal needs to be performed, it is a matter of swapping the references (and back-references) to the head and tail of that "k last element" sublist. Don't go over the whole sublist to change links between each pair of consecutive nodes. By removing the idea of prev/next, you can just leave those "internal" links as they are. Whenever you need to iterate through the list, you will always know which side you are coming from (i.e. what the "previous" node was), and so you can derive which of the neighbours must be the "next" one.
Here is an implementation of that idea in JavaScript. At the end of the code the algorithm is executed for the example input you have given:
class Node {
constructor(x, neighbor1=null, neighbor2=null) {
this.x = x;
this.neighbors = [neighbor1, neighbor2]; // No specific order...
}
opposite(neighbor) {
// Return the neighbor that is on the other side of the argument-neighbor
return this.neighbors[1 - this.neighbors.indexOf(neighbor)];
}
replaceNeighbor(find, repl) {
let i = this.neighbors.indexOf(find);
this.neighbors[i] = repl;
}
}
class List {
constructor(k) {
this.nodeCount = 0;
this.k = k;
// All node references are null:
this.head = this.tail = this.tailBeforeLastK = this.headOfLastK = null;
}
add(x) {
this.nodeCount++;
let node = new Node(x, this.tail, null);
if (this.head === null) {
this.headOfLastK = this.head = this.tail = node;
return;
}
this.tail.replaceNeighbor(null, node);
this.tail = node;
if (this.nodeCount > this.k) { // Move the head of the "last K" sublist
[this.tailBeforeLastK, this.headOfLastK] =
[this.headOfLastK, this.headOfLastK.opposite(this.tailBeforeLastK)];
}
}
reverse() {
if (this.nodeCount < 2 || this.k < 2) return;
// Exchange the links to the start/end of the K-last sublist
this.tail.replaceNeighbor(null, this.tailBeforeLastK);
if (this.tailBeforeLastK) {
this.tailBeforeLastK.replaceNeighbor(this.headOfLastK, this.tail);
this.headOfLastK.replaceNeighbor(this.tailBeforeLastK, null);
}
else this.head = this.tail;
// Swap
[this.tail, this.headOfLastK] = [this.headOfLastK, this.tail];
}
toArray() {
let result = [];
for (let prev = null, node = this.head; node; [prev, node] =
[node, node.opposite(prev)]) {
result.push(node.x);
}
return result;
}
}
// Example
let k = 3;
// null means: REVERSE, a number means: ADD <number>:
let actions = [1, 2, 3, 4, null, 5, 6, null];
let list = new List(k);
for (let action of actions) {
if (action === null) list.reverse();
else list.add(action);
}
console.log(list.toArray());
I have a linked list which is cyclic and I want to find out the total number of elements in this list. How to achieve this?
One solution that I can think of is maintaining two pointers. First pointer (*start) will always point to the starting node, say Node A.
The other pointer (*current) will be initialized as: current = start->next.
Now, just iterate each node with current -> next until it points to start.
And keep incrementing a counter: numberOfNodes++;
The code will look like:
public int countNumberOfItems(Node* start){
Node* current = start -> next;
int numberOfNodes = 1; //Atleast the starting node is there.
while(current->next != start){
numberOfNodes++;
current = current->next;
}
return numberOfNodes;
}
Let's say the list has x nodes before the loop and y nodes in the loop. Run the Floyd cycle detection counting the number of slow steps, s. Once you detect a meet point, run around the loop once more to get y.
Now, starting from the list head, make s - y steps, getting to the node N. Finally, run two slow pointers from N and M until they meet, for t steps. Convince yourself (or better prove) that they meet where the initial part of the list enters the loop.
Therefore, the initial part has s - y + t + 1 nodes, and the loop is formed by y nodes, giving s + t + 1 total.
You just want to count the nodes in your linked list right? I've put an example below. But in your case there is a cycle so you also need to detect that in order not to count some of the nodes multiple times.
I've corrected my answer there is now an ordinary count and count in loop (with a fast and slow pointer).
static int count( Node n)
{
int res = 1;
Node temp = n;
while (temp.next != n)
{
res++;
temp = temp.next;
}
return res;
}
static int countInLoop( Node list)
{
Node s_pointer = list, f_pointer = list;
while (s_pointer !=null && f_pointer!=null && f_pointer.next!=null)
{
s_pointer = s_pointer.next;
f_pointer = f_pointer.next.next;
if (s_pointer == f_pointer)
return count(s_pointer);
}
return 0;
}
First find the cycle using Floyd Cycle Detection algorithm and also maintain count when you checking cycle once found loop then print count for the same.
function LinkedList() {
let length = 0;
let head = null;
let Node = function(element) {
this.element = element;
this.next = null;
}
this.head = function() {
return head;
};
this.add = function(element) {
let node = new Node(element);
if(head === null){
head = node;
} else {
let currentNode = head;
while(currentNode.next) {
currentNode = currentNode.next;
}
currentNode.next = node;
}
};
this.detectLoopWithCount = function() {
head.next.next.next.next.next.next.next.next = head; // make cycle
let fastPtr = head;
let slowPtr = head;
let count = 0;
while(slowPtr && fastPtr && fastPtr.next) {
count++;
slowPtr = slowPtr.next;
fastPtr = fastPtr.next.next;
if (slowPtr == fastPtr) {
console.log("\n Bingo :-) Cycle found ..!! \n ");
console.log('Total no. of elements = ', count);
return;
}
}
}
}
let mylist = new LinkedList();
mylist.add('list1');
mylist.add('list2');
mylist.add('list3');
mylist.add('list4');
mylist.add('list5');
mylist.add('list6');
mylist.add('list7');
mylist.add('list8');
mylist.detectLoopWithCount();
There is a "slow" pointer which moves one node at a time. There is a "fast" pointer which moves twice as fast, two nodes at a time.
A visualization as slow and fast pointers move through linked list with 10 nodes:
1: |sf--------|
2: |-s-f------|
3: |--s--f----|
4: |---s---f--|
5: |----s----f|
At this point one of two things are true: 1) the linked list does not loop (checked with fast != null && fast.next != null) or 2) it does loop. Let's continue visualization assuming it does loop:
6: |-f----s---|
7: |---f---s--|
8: |-----f--s-|
9: |-------f-s|
10: s == f
If the linked list is not looped, the fast pointer finishes the race at O(n/2) time; we can remove the constant and call it O(n). If the linked list does loop, the slow pointer moves through the whole linked list and eventually equals the faster pointer at O(n) time.
I wanted to sort a linked list containing 0s, 1s or 2s. Now, this is clearly a variant of the Dutch National Flag Problem.
http://en.wikipedia.org/wiki/Dutch_national_flag_problem
The algorithm for the same as given in the link is:
"Have the top group grow down from the top of the array, the bottom group grow up from the bottom, and keep the middle group just above the bottom. The algorithm stores the locations just below the top group, just above the bottom, and just above the middle in three indexes. At each step, examine the element just above the middle. If it belongs to the top group, swap it with the element just below the top. If it belongs in the bottom, swap it with the element just above the bottom. If it is in the middle, leave it. Update the appropriate index. Complexity is Θ(n) moves and examinations."
And a C++ implementation given for the same is:
void threeWayPartition(int data[], int size, int low, int high) {
int p = -1;
int q = size;
for (int i = 0; i < q;) {
if (data[i] == low) {
swap(data[i], data[++p]);
++i;
} else if (data[i] >= high) {
swap(data[i], data[--q]);
} else {
++i;
}
}
}
My only question is how do we traverse back in a linked list like we are doing here in an array?
A standard singly-linked list doesn't allow you to move backwards given a linked list cell. However, you could use a doubly-linked list, where each cell stores a next and a previous pointer. That would let you navigate the list forwards and backwards.
However, for the particular problem you're trying to solve, I don't think this is necessary. One major difference between algorithms on arrays and on linked lists is that when working with linked lists, you can rearrange the cells in the list to reorder the elements in the list. Consequently, the algorithm you've detailed above - which works by changing the contents of the array - might not actually be the most elegant algorithm on linked lists.
If you are indeed working with linked lists, one possible way to solve this problem would be the following:
Create lists holding all values that are 0, 1, or 2.
Remove all cells from the linked list and distribute them into the list of elements that are equal to 0, 1, or 2.
Concatenate these three lists together.
This does no memory allocation and purely works by rearranging the linked list cells. It still runs in time Θ(n), which is another plus. Additionally, you can do this without ever having to walk backwards (i.e. this works on a singly-linked list).
I'll leave the complete implementation to you, but as an example, here's simple C++ code to distribute the linked list cells into the zero, one, and two lists:
struct Cell {
int value;
Cell* next;
}
/* Pointers to the heads of the three lists. */
Cell* lists[3] = { NULL, NULL, NULL };
/* Distribute the cells across the lists. */
while (list != NULL) {
/* Cache a pointer to the next cell in the list, since we will be
* rewiring this linked list.
*/
Cell* next = list->next;
/* Prepend this cell to the list it belongs to. */
list->next = lists[list->value];
lists[list->value] = list;
/* Advance to the next cell in the list. */
list = next;
}
Hope this helps!
As others have said, there is no way to "back up" in a linked list without reverse links. Though it's not exactly an answer to your question, the sort can be easily accomplished with three queues implementing a bucket sort with three buckets.
The advantage of queues (vice pushing on stacks) is that the sort is stable. That is, if there are data in the list nodes (other than the 0,1,2-valued keys), these will remain in the same order for each key.
This is only one of many cases where the canonical algorithm for arrays is not the best for lists.
There is a very slick, simple way to implement the queues: circularly linked lists where the first node, say p, is the tail of the queue and consequently p->next is is the head. With this, the code is concise.
#include <stdio.h>
#include <stdlib.h>
typedef struct node_s {
struct node_s *next;
int val;
int data;
} NODE;
// Add node to tail of queue q and return the new queue.
NODE *enqueue(NODE *q, NODE *node)
{
if (q) {
node->next = q->next;
q->next = node;
}
else node->next = node;
return node;
}
// Concatenate qa and qb and return the result.
NODE *cat(NODE *qa, NODE *qb)
{
NODE *head = qa->next;
qa->next = qb->next;
qb->next = head;
return qb;
}
// Sort a list where all values are 0, 1, or 2.
NODE *sort012(NODE *list)
{
NODE *next = NULL, *q[3] = { NULL, NULL, NULL};
for (NODE *p = list; p; p = next) {
next = p->next;
q[p->val] = enqueue(q[p->val], p);
}
NODE *result = cat(q[0], cat(q[1], q[2]));
// Now transform the circular queue to a simple linked list.
NODE *head = result->next;
result->next = NULL;
return head;
}
int main(void)
{
NODE *list = NULL;
int N = 100;
// Build a list of nodes for testing
for (int i = 0; i < N; ++i) {
NODE *p = malloc(sizeof(NODE));
p->val = rand() % 3;
p->data = N - i; // List ends up with data 1,2,3,..,N
p->next = list;
list = p;
}
list = sort012(list);
for (NODE *p = list; p; p = p->next)
printf("key val=%d, data=%d\n", p->val, p->data);
return 0;
}
This is now a complete simple test and it runs just fine.
This is untested. (I will try to test it if I get time.) But it ought to be at least very close to a solution.
Using a doubly linked list. If you have already implemented a linked list object and the related link list node object, and are able to traverse it in the forward direction it isn't a whole bunch more work to traverse in the reverse direction.
Assuming you have a Node object somewhat like:
public class Node
{
public Node Next;
public Object Value;
}
Then all you really need to do is change you Node class and you Insert method(s) up a little bit to keep track of of the Node that came previously:
public class Node
{
public Node Next;
public Node Previous;
public Object Value;
}
public void Insert(Node currentNode, Node insertedNode)
{
Node siblingNode = currentNode.Next;
insertedNode.Previous = currentNode;
insertedNode.Next = siblingNode;
if(siblingNode!= null)
siblingNode.previous = insertedNode;
currentNode.next = insertedNode;
}
PS Sorry, I didn't notice the edit that included the C++ stuff so it's more C#
Works for all cases by CHANGING NODES rather than NODE DATA.. Hoping its never too late!
METHOD(To throw some light on handling corner cases):
1. Keep three dummy nodes each for 0,1,2;
2. Iterate throught the list and add nodes to respective list.
3. Make the next of zero,one,two pointers as NULL.
4. Backup this last nodes of each list.
5. Now handle 8 different possible cases to join these list and Determine the HEAD.
zero one two
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
An implementation of this in C++.
Node* sortList(Node *head)
{
struct Node dummyzero,dummyone,dummytwo;
dummyzero.next = dummyone.next = dummytwo.next = NULL;
struct Node *zero =&dummyzero,*one = &dummyone,*two=&dummytwo;
Node *curr = head,*next=NULL;
while(curr)
{
next = curr->next;
if(curr->data==0)
{
zero->next = curr;
zero = zero->next;
}
else if(curr->data==1)
{
one->next = curr;
one = one->next;
}
else
{
two->next = curr;
two = two->next;
}
curr = next;
}
zero->next = one->next = two->next =NULL; //Since this dummynode, No segmentation fault here.
Node *zerolast = zero,*onelast = one,*twolast = two;
zero = dummyzero.next;
one = dummyone.next;
two = dummytwo.next;
if(zero==NULL)
{
if(one==NULL)
head = two;
else
{
head = one;
onelast->next = two;
}
}
else
{
head = zero;
if(one==NULL)
zerolast->next = two;
else
{
zerolast->next = one;
onelast->next = two;
}
}
return head;
}
The idea is to use dutch flag sorting algorithm, with a slight modification:
sort 0's and 1's as per dutch flag method,
But for 2's instead of adding them at the end of list, keep them in a separate linked list.
And finally append the 2's list to the sorted list of 0's and 1's.
Node * sort012_linked_list(Node * head) {
if (!head || !head->next)
return head;
Node * head_of_2s = NULL;
Node * prev = NULL;
Node * curr = head;
while (curr) {
if (curr->data == 0) {
if (prev == NULL || prev->data == 0) {
prev = curr;
curr = curr->next;
}
else {
prev->next = curr->next;
curr->next = head;
head = curr;
curr = prev->next;
}
}
else if (curr->data == 1) {
prev = curr;
curr = curr->next;
}
else { // curr->data == 2
if (prev == NULL) {
head = curr->next;
curr->next = head_of_2s;
head_of_2s = curr;
curr = head;
}
else {
prev->next = curr->next;
curr->next = head_of_2s;
head_of_2s = curr;
curr = prev->next;
}
}
}
if (prev)
prev->next = head_of_2s;
return head;
}