I had heard this question from my friend who attended an interview recently:
Given the head of the linked list, Write a function to swap the head with the next element in the linked list and return the pointer to the new head.
Ex:
i/p: 1->2,3,4,5 (the given head is 1)
o/p: 2->1,3,4,5
Assuming
struct node {
struct node *next;
};
struct node *head;
then the solution might look something like
struct node *next = head->next;
if(next == NULL) return head; // nothing to swap
head->next = next->next;
next->next = head;
head = next;
return next;
struct node* head;
struct node *tmp1,*tmp2;
tmp1=head; // save first node pointer
tmp2=head->next->next; // save third node pointer
head=head->next; // Move Head to the second node
head->next=tmp1; // swap
head->next->next=tmp2; // Restore the link to third node
Related
Given a singly linked list where each element contains a number and a pointer to the head of the list. Sum the first and last data and remove these nodes. Then sum the first and last data of the resulting linked list and remove these two nodes.
Keep doing this till the list becomes empty.
we have to find the maximum sum obtained from the resulting sum in O(1) space complexity.
The list is a singly linked list with even nodes.
My Thoughts:
One approach is to move the pointer to the last element at each iteration, remove the nodes, and keep a maxSum variable. This probably won't be an efficient solution.
If I understood correctly, a node in this linked list has two pointers: a pointer to the next node and one to the first node in the list.
There are several ways to solve this. Here is one:
Walk through the list and change the head pointer in each node to reference the previous node: this will give you a doubly linked list. Retain a pointer to the last node.
Now you can do a traversal in tandem starting at both ends of the list and walking towards each other.
Deleting nodes during that traversal is not really required. You could even restore the list to what it was originally in the second step.
It is even possible to do this without this extra head pointer in each node. In that case reverse the second half of the list.
Here is an implementation of the first idea, in JavaScript:
class Node {
constructor(data, head) {
this.data = data;
this.head = head || this; // default is node itself
this.next = null;
}
}
function createList(...values) {
if (!values) return null;
let head = new Node(values.shift()); // First value
let tail = head;
for (let value of values) { // Remaining values
tail.next = new Node(value, head);
tail = tail.next;
}
return tail.head;
}
function maxPairSum(head) {
if (!head) return -Infinity;
// Make doubly linked list, (ab)using node's head member
let tail;
for (tail = head; tail.next; tail = tail.next) {
tail.next.head = tail; // Next gets reference to previous
}
// Tandem walk, towards center
let maxSum = -Infinity;
for (let curr = head; curr != tail && curr != tail.next; curr = curr.next) {
maxSum = Math.max(maxSum, curr.data + tail.data);
tail = tail.head; // Is actually a reference to previous
}
// Restore head references (optional)
for (let curr = head; curr; curr = curr.next) {
curr.head = head;
}
return maxSum;
}
// Example run
let head = createList(2, 5, 1, 5, 4, 6);
let maxSum = maxPairSum(head);
console.log(maxSum); // 9
... And if you want to really remove the list, just clear the head reference. In JavaScript the garbage collector will free the unreachable memory; in some other languages (like C) you'll need to explicitly free the memory occupied by each node, before clearing the reference to the head node.
private static int max = 0, count = 0;
private static LinkedList top;
static int maximumPagesRec(LinkedList tail) {
if(tail.next==null)
max = max<top.data + tail.data ?top.data + tail.data: max;
else if(tail == top && count++ !=0){
max = max<top.data ?tail.data: max;
}
else if(top.next == tail && count++!=1)
max = max<top.data + tail.data ?top.data + tail.data: max;
else {
maximumPagesRec(tail.next);
}
top = top.next;
return max;
}
static int maximumPages(LinkedList head)
{ top = head;
return maximumPagesRec(head);
}
how about pushing all linked list value element to a stack, take 1->2->3->4 for example, and the stack will be 1234.
after that, we sum one by one and delete each linked list, store maximum value we got.
#include <stdio.h>
#include <stdlib.h>
Node Creation
This structure creates the struct node data type
struct node
{
int data;
struct node *left, *right;
} * newnode;
Create Function
create() - It first allocates the memory required for the node. When user enters the data, it recursively calls itself to create its child node, and this process goes on. When the user enters -1, it terminates the recursion and goes back from where it is called.
struct node *create()
{
int x;
newnode = (struct node *)malloc(sizeof(struct node));
newnode->left = 0;
newnode->right = 0;
printf("Enter data(-1 for no node)\n");
scanf("%d", &x);
if (x == -1)
return 0;
newnode->data = x;
printf("Enter left child of %d\n", x);
newnode->left = create();
printf("Enter right child of %d\n", x);
newnode->right = create();
return newnode;
}
Preorder
preorder(struct node *root) - This function displays the data of the tree in preorder manner
void preorder(struct node *root)
{
if (root == 0)
return;
printf("%d\n", root->data);
preorder(root->left);
preorder(root->right);
}
Inorder
inorder(struct node *root) - This function displays the data of the tree in inorder manner
void inorder(struct node *root)
{
if (root == 0)
return;
inorder(root->left);
printf("%d\n", root->data);
inorder(root->right);
}
Postorder
Postorder(struct node *root) - This function displays the data of the tree in postorder manner
void postorder(struct node *root)
{
if (root == 0)
return;
postorder(root->left);
postorder(root->right);
printf("%d\n", root->data);
}
Main Function
Main function asks the user to create a tree and then traverse it according to the choice entered by the user. The problem is that preorder, inorder and postorder are not giving the required output, and result in an infinite loop after execution.
void main()
{
struct node *root;
root = 0;
int choice = 3, opt = 1;
while (opt)
{
printf("Select\n 1-for creation\n 2-for preorder\n 3-for inorder\n 4-for postorder\n");
scanf("%d", &choice);
switch (choice)
{
case 1:
root = create();
break;
case 2:
printf("Preorder is: ");
preorder(root);
break;
case 3:
printf("Inorder is: ");
inorder(root);
break;
case 4:
printf("Postorder is: ");
postorder(root);
break;
default:
printf("Invalid choice");
break;
}
printf("Wanna continue \n1-for yes\n0-for no\n");
scanf("%d", &opt);
}
}
There is no bug with any of the traversal functions you've provided.
No design or implementation problem with create () function either.
The trouble lies in the global struct node pointer newnode declared with the structure's definition.
Because each recursive call to create () is basically using the "same" newnode pointer, the tree is never really built in the way we want it to.
Let's try to dry run the create () function.
Let's say we want a tree like this:
1
/ \
2 3
create () is first called from main.
The memory is allocated using malloc () function and the address of the memory is stored in newnode.
Set it's attributes, left and right.
Ask for data and put it into data attribute, if data == -1 is true, return 0.
Up until this point, this is the state:
newnode -> 1
/ \
Null Null
create () is recursively called to build the left subtree.
The memory is allocated for newnode using malloc () and the address of the memory is stored in newnode. Note that this operation has basically "over-wrote" the address previously stored in newnode (because newnode is a global variable)
Then again, the user will be prompted for the data and its attributes will be set.
Therefore, the tree has now become:
newnode -> 2
/ \
Null Null
The struct node to which newnode was previously pointing is now lost (because of loss of its address)
Similarly, when the recursive call for the right subtree is made, then, the following will be observed:
newnode -> 3
/ \
Null Null
Considering the same scenario for the rest of the recursive calls made, it is clear that in the end, the tree we were expecting wasn't built and the reason is the global variable newnode, the constant allocation of memory and over-writing the address in newnode led to memory leakage only.
The reason infinite recursion was found is that, during multiple recursive calls, the left or right pointer of newnode was made to point to newnode itself, leading to a cycle. This node can be found by closely tracking the data of newnode during the recursive calls.
Hence, remove the declaration of newnode pointer from the structure declaration and modify the following statement in create () function:
newnode = (struct node *)malloc(sizeof(struct node));
to this:
struct node * newnode = (struct node *)malloc(sizeof(struct node));
And
struct node
{
int data;
struct node *left, *right;
};
is all what's needed.
In this way, each recursive call to create () function will have its own local pointer variable newnode and there will be no overwriting, no leakage, no cycle, no infinite recursion.
A signle link list, i want revese it by recursion. but i don't understand the meaning of this line head->next->next = head;.
why there need head->next->next?
struct Node{
int data;
Node* next;
};
Here is the implement code:
Node* reverseByRecursion(Node *head)
{
if(head == NULL || head->next == NULL)
return head;
Node *newHead = reverseByRecursion(head->next);
head->next->next = head;
head->next = NULL;
return newHead;
}
Let me work with this list.
reverseByRecursion(node1) is called.
Neither node1 nor node1->next is NULL, so newHead = reverseByRecursion(head2); is called.
Neither node2 nor node2->next is NULL, so newHead = reverseByRecursion(head3); is called.
head3->next is NULL, so head3 is returned from reverseByRecursion(head2).
head = node2 and head->next = node3, so head->next->next = head; will set node3->next to node2.
head->next = NULL; will set node2->next to NULL. (image 2)
newHead, which is node3, is returned from reverseByRecursion(head2).
head = node1 and head->next = node2, so head->next->next = head; will set node2->next to node1.
head->next = NULL; will set node1->next to NULL. (image 3)
newHead, which is node3, is returned from reverseByRecursion(node1).
Now the list is reversed with having node3 as the head.
image 2
image 3
try to understand it this way, .next actually meant to change the arrow pointing to the next value. So
head.next.next = head
means adding an arrow from the next next position and point it back to head
Hope this is more intuitive to understand
Your base case says that if there are no more elements, then the current node becomes the head of the list.
The head->next->next = head line means that the next node is being reused with its pointer pointing backward (in the opposite direction as before). Since the node used to be the NEXT node after the current node, it becomes the PREVIOUS node before the current head, and its next pointer therefore ought to point to the current node ("head").
if you want create a singly linked list like this:
struct Node {
int data;
Node *next;
};
struct List{
Node *head;
// Node *tail; --> necessary?
Node *last;
};
And this list has the methods "append", "remove", "printList" and "findElement".
Is it necessary to have a tail? Because with "last" you can address the last node.
So when it is necessary to have all three Nodes "head", "tail" and "last"? When you want to insert the node sorted into the list for example?
No, it's not necessary. The tail is equal to head->next and thus it would be redundant and add bookkeeping overhead to keep this field updated.
Also note that the field last is kind of unusual. In most use cases, you add elements to the head of a singly linked list and use a different data structure when you really need to add to the end.
Actually, you can implement enqueue (append at tail), push (prepend at head), dequeue (remove from head), and of course find and print with with a one-pointer header. The trick is to make the list circular and have the header point to the tail. Then tail->next is the head.
#include <stdio.h>
#include <stdlib.h>
typedef struct node_s {
struct node_s *next;
int data;
} Node;
typedef struct list_s {
Node *tail;
} List;
Node *new_node(int data) {
Node *node = malloc(sizeof *node);
node->data = data;
node->next = node;
return node;
}
void init_list(List *list) {
list->tail = NULL;
}
int is_empty(List *list) {
return list->tail == NULL;
}
void enqueue(List *list, Node *node) {
if (list->tail) {
Node *head = list->tail->next;
node->next = head;
list->tail->next = node;
list->tail = node;
} else list->tail = node->next = node;
}
void push(List *list, Node *node) {
if (list->tail) {
Node *head = list->tail->next;
node->next = head;
list->tail->next = node;
} else list->tail = node->next = node;
}
Node *dequeue(List *list) {
Node *head = list->tail->next;
if (head == list->tail)
list->tail = NULL;
else
list->tail->next = head->next;
return head;
}
void print_list(List *list) {
printf("The list:\n");
if (list->tail) {
Node *head = list->tail->next;
Node *p = head;
do {
printf("%d\n", p->data);
p = p->next;
} while (p != head);
}
}
int main(int argc, char *argv[]) {
List list[1];
init_list(list);
// Build the list in order and print it.
for (int i = 0; i < 4; i++) enqueue(list, new_node(i));
print_list(list);
// Remove elements from head until empty.
printf("Dequeueing:\n");
while (!is_empty(list)) {
Node *node = dequeue(list);
printf("%d\n", node->data);
free(node);
}
// Build the list in reverse order and print it.
for (int i = 0; i < 4; i++) push(list, new_node(i));
print_list(list);
return 0;
}
I think it depends on what operations you want to use.
Assuming you want to insert and delete nodes at the tail of a list, it is certainly a wise choice to keep a last node in your list.
Otherwise, if you want to do operations at the beginning of the list, a last node is unnecessary.
It's not necessary but a tail can be useful if you're working with the linked list in a queue-like FIFO fashion rather than a stack-like LIFO fashion or want to be able to transfer entire lists of elements from one head to another's tail without disrupting the relative order of the elements.
Note that I'm referring to 'tail' as a reference to the last node in the list which I believe is safe to assume that the question is about.
A lot of very micro-optimized SLL implementations often are tail-less and work like a stack while backed by an efficient fixed allocator for locality of reference (cache-friendliness) and faster node allocations/deallocations. There the primary benefit of the SLL over a variable-sized array-based sequence is the ability to start moving things around by just changing the value of the next pointer/reference and the lack of invalidation on inserting/removing elements if you're working in native, lower-level languages that involve pointers. The lack of a tail can boost performance quite a bit by reducing the amount of branching instructions required in operations to push and pop from the stack.
For the needs you listed, whether the tail is going to help or just add unnecessary complexity and overhead is if your append and remove operations can work strictly from the front in a LIFO stack fashion or if you want to be able to append to the back but remove from the front in a FIFO fashion without any iteration involved, e.g. If you don't have a tail in the latter case, one of these operations are going to go from constant-time complexity to linear-time complexity, and you might improve your use cases by exchanging that linear-time algorithmic complexity for the relatively smaller micro-level overhead of maintaining a tail.
The following is the structure
struct list *node
{
int data;
struct list *next;
}
What does node=node->next exactly do while traversing the linked list and isn't the next element pointer to pointer in the node variable?
Imagine incrementing a variable with a while loop.
int i = 0;
while (i < 6) {
// this loop will run forever without the line below
i++; // adds one to i so the loop will not run infinitely
}
The concept is the same with linked lists:
while (node != NULL) {
//need to make sure this loop doesn't run forever
node = node->next // kind of like incrementing i
}
Now the while loop will run until the end of the list is reached.
node = node->next makes node point towards next pointer in linked list.
As the value stored in next is pointer to next element in the list.
So making node as node->next and then calling the function again or iterating in the for loop makes you go forward.
Hope that helps