Swap items in a doubly linked list - c

I am studying for my Algorithms exam and I have an exercise where I need to swap two items of a doubly linked list if a condition is true. (Language: C)
More specifically, I have a list of this kind:
H <-> |prev|Frequency1|VALUE1|next| <-> |prev|Frequency2|VALUE2|next| <-> ... <-> NULL
The frequency field increases every time I search for the relative value. The list must be ordered according to the frequency (in decreasing order, so at the very top there is the most searched item)
The problem is, I am not very good in exchanging pointers, I tried many times to do it but I have no clue. I guess that the problem I am facing is that I don't know how to use a temp item to keep track of what I am doing without loosing data.
I think that the case I have to consider are:
First item of the list
Last item of the list
Item is in the middle of the list.
My attempt, certainly wrong is:
int Search(int x, list* head) {
int contapos = 0;
list* i;
list* aus;
for (i=head; i!=NULL; i = i->next, contapos++)
{
if (i->key == x)
{
i->freq++; // Increase frequency
aus = i->prev;
while ((i->freq > aus->freq))
{ // Keep ordered the frequencies
if (i->next != NULL)
{
i->next->prev = aus;
}
if (aus->prev != NULL)
{
aus->prev->next = i;
}
aus->next = i->next;
i->prev = aus->prev;
aus->prev = i;
i->next = aus;
}
/* Return counter */
return contapos;
}
}
return -1; // In case the item i am searching is not there
}
Thank you in advance for everything!
Edit:
as requested, I am adding the main (and the whole code just to be sure) of the program at the moment
typedef struct _list {
int key;
int freq;
struct _list *next;
struct _list *prev;
} list;
list* head;
list* tail;
void swap(list *lhs, list *rhs) {
list *temp;
temp = lhs->prev;
lhs->prev = rhs->prev;
rhs->prev = temp;
temp = lhs->next;
lhs->next = rhs->next;
rhs->next = temp;
}
void InsertAtTail(int value) {
list *newNode;
newNode = (list*)malloc(sizeof(list));
newNode->key = value;
if(head == NULL)
{
head = newNode;
}
else
{
tail->next = newNode;
newNode->prev = tail;
}
tail = newNode;
tail->next = NULL;
}
int SearchAndIncrement(int x, list** head) {
int contapos = 0;
list* i;
// Let's find the element with the matching key
for (i = *head; i != NULL; i = i->next, contapos++)
if (i->key == x)
break;
// If we did not find the node, return -1 to denote failure.
if (i == NULL)
return -1;
// Increase frequency
i->freq++;
// Move this node forward while the frequency is not in the correct position.
while (i->next && i->prev && (i->freq > i->prev->freq))
swap(i, i->prev);
// The head might have been moved.
while ((*head)->prev != NULL)
(*head) = (*head)->prev;
// Return the original position
return contapos;
}
int main () {
int N;
scanf("%d", &N);
head = NULL;
tail = NULL;
int i, value;
for (i=0; i<N; i++) {
scanf("%d", &value);
InsertAtTail(value);
}
/* Initializing frequencies */
list* aus;
for (aus=head; aus; aus = aus ->next) {
aus->freq = 0;
}
int x, pos;
do {
scanf("%d", &x);
pos = SearchAndIncrement(x, &head);
printf("%d ", pos);
printf("[");
aus = head;
while (aus!=NULL) {
printf("%d ", aus->key);
aus = aus->next;
}
printf("]\n");
} while (pos != -1);
return 0;
}

Let's simplify the problem. The complicated pointer portion is when we are trying to move a node forward in the list. So let's create some functions just for that.
void RemoveNode(list *node) {
if (node->prev)
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
}
void InsertNodeBetween(list *lhs, list *node, list *rhs) {
if (lhs) assert(lhs->next == rhs);
if (rhs) assert(rhs->prev == lhs);
if (lhs) lhs->next = node;
if (rhs) rhs->prev = node;
node->prev = lhs;
node->next = rhs;
}
Once we've done that, then we can more easily talk about the operation that you want to do.
int SearchAndIncrement(int x, list** head) {
int contapos = 0;
list* i;
// Let's find the element with the matching key
for (i = *head; i != NULL; i = i->next, contapos++)
if (i->key == x)
break;
// If we did not find the node, return -1 to denote failure.
if (i == NULL)
return -1;
// Increase frequency
i->freq++;
// Move this node forward while the frequency is not in the correct position.
while (i->next && (i->freq > i->next->freq)) {
list *prev = i->next;
list *next = i->next->next;
RemoveNode(i);
InsertNodeBetween(prev, i, next);
}
// The head might have been moved.
while ((*head)->prev != NULL)
(*head) = (*head)->prev;
// Return the original position
return contapos;
}
Some commentary:
The important thing to note here is that we have the ability to create multiple functions. And we can use those functions to make the amount of the problem that we need to keep in our head at any one time smaller.

Related

What is the error in this code that checks if the linklist is a palindrome or not?

this function reverses the linklist.
ListNode *reverseLL(ListNode*);
int nodeCounter(struct ListNode* head){
struct ListNode* ptr=head;
int counter=0;
while(ptr!=NULL){
counter++;
printf("%d ",ptr->val);
ptr=ptr->next;
}
return counter;
}
this function does the checking
bool isPalindrome(struct ListNode* head){
struct ListNode *revhead=reverseLL(head);
int length=nodeCounter(head),mid=length/2,count=0;
struct ListNode *ptr=head;
struct ListNode *ptr1=revhead;
while(length!=mid){
printf("\n %d == %d",ptr->val,ptr1->val);
if(ptr->val!=ptr1->val){
printf("in");
return 0;
}
ptr=ptr->next;
ptr1=ptr1->next;
length--;
}
return true;
}
It works fine in most cases but when input is 1,2,1,1 it fails.
Assuming that you can not change ListNode (by adding a struct ListNode *prev;), allocate an array of pointers to nodes to create the "reverse" list:
bool
isPalindrome(struct ListNode *head)
{
struct ListNode *left;
int ispal = 1;
// count number of elements in list
int count = 0;
for (left = head; left != NULL; left = left->next)
++count;
do {
// handle empty list
if (count == 0) {
ispal = 0;
break;
}
// handle list with one element
if (count < 2)
break;
// get the middle
int mid = count / 2;
// NOTE: using static here reduces the number of allocations
static struct ListNode **revlist = NULL;
static int maxalloc = 0;
// increase size of the "reverse" array
if (count > maxalloc) {
maxalloc = count + 100;
revlist = realloc(revlist,sizeof(*revlist) * maxalloc);
if (revlist == NULL) {
perror("realloc");
exit(1);
}
}
int ridx;
// fill the array right to left to create "reversed" list
ridx = count - 1;
for (left = head; left != NULL; left = left->next, --ridx)
revlist[ridx] = left;
// compare the left/right nodes
ridx = 0;
for (left = head; ridx < mid; left = left->next, ++ridx) {
struct ListNode *right = revlist[ridx];
if (left->val != right->val) {
ispal = 0;
break;
}
}
} while (0);
return ispal;
}
Assuming you can add the prev pointer to your struct [the list remains a singly linked list but we add the extra pointer]:
bool
isPalindrome(struct ListNode *head)
{
struct ListNode *left = head;
struct ListNode *right;
struct ListNode *prev;
int ispal = 1;
do {
// handle empty list
if (left == NULL) {
ispal = 0;
break;
}
// create previous pointers
prev = NULL;
for (; left != NULL; left = left->next) {
left->prev = prev;
prev = left;
}
// point to head of list
left = head;
// point to tail of list
right = prev;
// handle list with one element
if (left == right)
break;
// compare the left/right nodes
while (1) {
if (left->val != right->val) {
ispal = 0;
break;
}
// detect crossing for even numbered list
left = left->next;
if (left == right)
break;
// detect crossing for odd numbered list
right = right->prev;
if (left == right)
break;
}
} while (0);
return ispal;
}
If you can have a full doubly linked list and have a separate "list" struct (e.g.):
bool
isPalindrome(struct List *list)
{
struct ListNode *left = list->head;
struct ListNode *right = list->tail;
int ispal = 1;
do {
// handle empty list
if (left == NULL) {
ispal = 0;
break;
}
// handle list with one element
if (left == right)
break;
// compare the left/right nodes
while (1) {
if (left->val != right->val) {
ispal = 0;
break;
}
// detect crossing for even numbered list
left = left->next;
if (left == right)
break;
// detect crossing for odd numbered list
right = right->prev;
if (left == right)
break;
}
} while (0);
return ispal;
}
One of the reasons you may be discouraged is that using "competition" websites like "leetcode" [or "hackerrank"] are not the best way to learn programming.
It's better to start with some good books: The Definitive C Book Guide and List
Also, better online sites to learn programming come from universities that have put courses online (free for students/anybody):
https://cs50.harvard.edu/college/2022/spring/ (Harvard cs50)
https://cs50.harvard.edu/college/2022/fall/ (Harvard cs50)
https://ocw.mit.edu/ (MIT's open courseware)
https://www.coursera.org/ (Coursera online learning)
https://www.coursera.org/caltech (Caltech on Coursera)
https://online.stanford.edu/free-courses (Stanford University)
cs50 has a separate tag on stackoverflow (i.e.) cs50. And, a separate stack exchange website: https://cs50.stackexchange.com/

display output in `ascending` or `descending` order after storing value using linked list in c

I am storing five different values using from user input. And displaying as it is inserted from the command prompt, now I want to organize the output as ascending or descending order during display. I searched for this, but I am getting more complicated examples. My code is pretty simple. I am learning. Till now, what I did already, if I can implement ascending or descending order in my code, then it will be more help to me for easy understand. Would someone help me please to do this, if possible in my existing code.
#include <stdio.h>
struct list{
int value;
struct list *next;
};
int main(){
struct list list1[5], *c;
int i = 0;
for(i = 0; i < 5; i++){
printf("Enter value of list %d = ", i);
scanf("%d", &list1[i].value);
}
for(i = 0; i < 4; i++){
list1[i].next = &list1[i+1];
}
list1[4].next = NULL;
c = &list1[0];
while(c != NULL){
printf("List value: %d\n", c->value);
c = c->next;
}
return 0;
}
… implement ascending or descending order in my code … by changing the next pointers accordingly
You could use a kind of insertion sort to do this by going through your unsorted list and building a new list, reconnecting the next pointers in sorted order:
struct list *head = NULL, *nc; // new (initially empty) list starts at head
for (c = list1; c; c = nc) // go through original list
{
struct list **pred = &head, *d;
while ((d=*pred) && c->value > d->value) pred = &d->next; // find pos.
nc = c->next; // get next element (before overwritten)
c->next = d, *pred = c; // insert element into sorted list
}
This sorts ascending; for descending order, change > to <.
you can store the data in order instead. can follow this code to store data in sorted order :=
#include<stdio.h>
#include<stdlib.h>
struct List
{
struct List * next;
int node;
};
struct List * add(struct List * head, int data)
{
struct List * newnode = (struct List *)malloc(sizeof(struct List));
newnode->next = NULL;
newnode->node = data;
/* if list is empty (initially), put value */
if(head == NULL)
{
head = newnode;
return head;
}
/* if head itself smaller than the node to be inserted
the sign(<) has to be changed(>) for ascending order.
*/
else if(head->node > data)
{
newnode->next = head;
head = newnode;
return head;
}
struct List * temp = head;
struct List * current = NULL;
while(temp->next)
{
current = temp;
/*if node is fitted between current node and next of current node..
the sign(>=) has to be changed(<=) and the sign (<=) has to be changed (>=)for ascending order .
*/
if(current->node <= data && current->next->node >= data)
{
newnode->next = current->next;
current->next = newnode;
return head;
}
temp = temp->next;
}
temp->next = newnode;
return head;
}
void display(struct List * head)
{
if(head == NULL)
return;
printf("%i ", head->node);
display(head->next);
}
int main(void){
int arr[] = {3, 0, 1, 4, 2};
int n = sizeof(arr)/sizeof(1);
struct List * head = NULL;
for(int i=0; i<n; i++){
head = add(head, arr[i]);
}
display(head);
printf("\n");
}

How to combine in one loop serial numbers and null?

I'm busy with implementation of singly linked list and have 2 functions: insert_back and insert_after.
Here is the listing of them:
void insert_back(int data)
{
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
while (temp1->next != NULL) {
temp1 = temp1->next;
}
node *temp;
temp = (node*)malloc(sizeof(node));
temp->data = data;
temp->next = NULL;
temp1->next = temp;
}
void insert_after(int pos, int data)
{
node *temp1;
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
for (int i = 1; i < pos; i++) {
temp1 = temp1->next;
if (temp1 == NULL) {
return;
}
}
node *temp;
temp = (node*)malloc(sizeof(node));
temp->data = data;
temp->next = temp1->next;
temp1->next = temp;
}
As you can see they are almost the same and for insert back I want to write insert_after(null, 10). I can solve it by adding if condition and choose one of the loops, but it's not my aim.
Is it possible somehow to use one while or for loops together for serial numbers and null?
Also I see that param int pos is int. Should I use 0 instead of null?
You unnecessarily allocate memory in the following lines.
temp1 = (node*)malloc(sizeof(node));
temp1 = head;
This allocated memory will leak as you overwrite the returned address in temp1. You just need temp1 to walk over the list, so there is also no need to allocate any node itself. temp1 can point to any node.
I've taken the liberty to kind of from scratch write a routine doing both things in one go. If pos < 0 it will add the element to the end of the list, otherwise it will add it after the pos-th element, where the first element corresponds with pos == 1. If pos == 0 the element is added at the start of the list.
Also a small main is added to test the routine. new_node has been added to test if memory is not exhausted.
#include <stdlib.h>
#include <stdio.h>
typedef struct node
{
struct node * next;
int data;
} node;
node * head = NULL;
node * new_node(void)
{
node * result = malloc(sizeof(*result));
if (result == NULL)
{
fprintf(stderr, "Out of memory.\n");
exit(10);
}
return result;
}
void insert_after(int pos, int data)
{
node *walk, * prev;
int i;
prev = NULL;
walk = head;
for (i = 0; walk != NULL && i != pos; i++)
{
prev = walk;
walk = walk->next;
}
if (i != pos && pos > 0)
{
fprintf(stderr, "Location not found.\n");
exit(9);
}
else
{
walk = new_node();
walk->data = data;
if (prev == NULL)
{
walk->next = head;
head = walk;
}
else
{
walk->next = prev->next;
prev->next = walk;
}
}
}
int main(void)
{
int i;
node * wlk;
for (i = 0; i < 10; i++)
{
insert_after(-1, i);
}
for (i = 0; i < 10; i++)
{
insert_after(3, i+10);
}
for (wlk = head; wlk != NULL; wlk = wlk->next)
{
printf("%d\n", wlk->data);
}
return 0;
}
Since you are testing for the end of the chain with insert_after(pos,...) anyway, you could go for:
void insert_after(int pos, int data)
{
node *temp1= head;
for (int i=1; i<pos; i++) {
if (temp1->next==NULL) {
if (pos==INT_MAX)
break; // pos of INT_MAX means insert at end
// so we continue with this last item and append
else
return; // pos higher than length of chain
}
temp1 = temp1->next;
}
...
}
Or slightly more compact:
void insert_after(int pos, int data)
{
node *temp1= head;
for (int i=1; i<pos && temp1->next!=NULL; i++) {
temp1 = temp1->next;
}
if (temp1->next==NULL && pos!=INT_MAX)
return; // pos higher than length of chain, except for
// INT_MAX (for that we just want to continue)
...
}
Then you could use
void insert_back(int data)
{
insert_after(INT_MAX, data);
}

Sorting a linked list in C

I'm trying to sort a linked list by finding the largest value, deleting it from its position, and then inserting it at the top of the list.
The difficulty I'm running into is the actual deleting and inserting at the top. The issue seems to be in the if condition in the while loop contained within the sortList function, but I'm not sure how to fix it.
Any help would be appreciated.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int num;
struct node *next;
} Node, *NodePtr;
void printList(NodePtr np);
NodePtr makeList(void);
NodePtr makeNode(int n);
NodePtr sortList(NodePtr list);
int main(void) {
NodePtr list;
printf("Enter numbers for the list (0 to end)\n");
list = makeList();
printList(list);
list = sortList(list);
printList(list);
return 0;
}
NodePtr makeList(void) {
NodePtr makeNode(int), np, top, last;
int n;
top = NULL;
if(scanf("%d", &n) != 1)n = 0;
while(n != 0) {
np = makeNode(n);
if(top == NULL)top = np;
else last->next = np;
last = np;
if(scanf("%d", &n)!=1)n=0;
}
return top;
}
void printList(NodePtr np) {
while(np != NULL) {
printf("%d\n", np->num);
np = np->next;
}
}
NodePtr makeNode(int n) {
NodePtr np = (NodePtr)malloc(sizeof(Node));
np->num = n;
np->next = NULL;
return np;
}
NodePtr sortList(NodePtr list) {
NodePtr top = list;
NodePtr curr = NULL;
NodePtr largest;
NodePtr prev;
prev = NULL;
curr = top;
largest = top;
while(curr != NULL) {
prev = curr;
if(curr->num > largest->num) {
largest = curr;
prev->next = curr->next;
largest->next = top;
}
curr = curr->next;
}
if(prev == NULL) {
largest->next = top;
return largest;
}
return largest;
}
There is issues in the sortList function.
This function only put some large nodes in the beginning of the list. It is not soting all the list. you can you a sort algorithm to sort the file : quicksort/ bubblesort/...
i put a code doing a sort in the end of this answer.
here is a code doing the sort of the list :
//it is replacing largest node with first one then doing the same operation with sublist (list-first element)
NodePtr sortList(NodePtr list)
{
//
if(list == null || list->next == null)
return list; // the list is sorted.
//replace largest node with the first :
//1- find largest node :
NodePtr curr, largest,largestPrev;
curr = list;
largest = list;
prev = list;
largestPrev = list;
while(curr != NULL) {
if(curr->num > largest->num) {
largestPrev = prev;
largest = curr;
}
prev = curr;
curr = curr->next;
}
//largest node is in largest.
//2- switching firt node and largest node :
NodePtr tmp;
if(largest != list)
{
largestPrev->next = list;
tmp = list->next;
list->next = largest->next;
largest->next = tmp;
}
// now largest is the first node of the list.
// calling the function again with the sub list :
// list minus its first node :
largest->next = sortList(largest->next);
return largest;
}
Here is my attempt to sort a singly linked list using QuickSort algorithm. If you know n then run time will be O(n log n). Check if this helps.
#include "malloc.h"
typedef struct node {
struct node *next;
int val;
} node;
bool insert_node(struct node **head, int val)
{
struct node *elem;
elem = (struct node *)malloc(sizeof(struct node));
if (!elem)
return false;
elem->val = val;
elem->next = *head;
*head = elem;
return true;
}
int get_lval(struct node *head, int l)
{
while(head && l) {
head = head->next;
l--;
}
if (head != NULL)
return head->val;
else
return -1;
}
void swap(struct node *head, int i, int j)
{
struct node *tmp = head;
int tmpival;
int tmpjval;
int ti = i;
while(tmp && i) {
i--;
tmp = tmp->next;
}
tmpival = tmp->val;
tmp = head;
while(tmp && j) {
j--;
tmp = tmp->next;
}
tmpjval = tmp->val;
tmp->val = tmpival;
tmp = head;
i = ti;
while(tmp && i) {
i--;
tmp = tmp->next;
}
tmp->val = tmpjval;
}
struct node *Quick_Sort_List(struct node *head, int l, int r)
{
int i, j;
int jval;
int pivot;
i = l + 1;
if (l + 1 < r) {
pivot = get_lval(head, l);
printf("Pivot = %d\n", pivot);
for (j = l + 1; j <= r; j++) {
jval = get_lval(head, j);
if (jval < pivot && jval != -1) {
swap(head, i, j);
i++;
}
}
swap(head, i - 1, l);
Quick_Sort_List(head, l, i);
Quick_Sort_List(head, i, r);
}
return head;
}
struct node *Sort_linkedlist(struct node *head)
{
struct node *tmp = head;
// Using Quick sort.
int n = 0;
while (tmp) {
n++;
tmp = tmp->next;
}
printf("n = %d\n", n);
head = Quick_Sort_List(head, 0, n);
return head;
}
void print_list(struct node *head)
{
while(head) {
printf("%d->", head->val);
head = head->next;
}
printf("\n");
}
int _tmain(int argc, _TCHAR* argv[])
{
struct node *head = NULL;
struct node *shead = NULL;
insert_node(&head, 10);
insert_node(&head, 12);
insert_node(&head, 9);
insert_node(&head, 11);
insert_node(&head, 7);
insert_node(&head, 1);
insert_node(&head, 3);
insert_node(&head, 8);
insert_node(&head, 5);
insert_node(&head, 2);
insert_node(&head, 4);
insert_node(&head, 6);
print_list(head);
shead = Sort_linkedlist(head);
print_list(shead);
return 0;
}
By writing to largest->next you overwrote curr->next. So you end up restarting from the top all the time.
Make sure that:
the list remains consistent
your list iterator remains consistent
But overall, your code seems to be heavily broken, I believe there might be a couple other errors in your sorting logic.
The following are some of the problems which exist in your sorting logic:
You are setting the prev pointer to curr in the beginning of the loop itself which is incorrect. By doing this, you are making the current pointer and the previous node pointer as same which makes it impossible to delete the node.
You should assign the largest pointer also to top whereby it facilitates the possibility of setting the largest->next to real top node.
The code can modified like below (Just a pointer, you need to check for other issues yourself):
while(curr != NULL)
{
if(curr->num > largest->num)
{
largest = curr;
prev->next = curr->next;
largest->next = top;
top = largest;
}
prev = curr;
curr = curr->next;
}
// Program to sort a single linked list in ascending order
// (without exchanging data in the nodes)
/**************************************************************************
There are two methods of sorting presented here(At a time,we can use any of
these two functions to sort our single linked list.) -
1. Function 'void Sort()' - This function uses selection sort method(I
think).
In this function,a node whose data is the smallest in the list is made
as 'head' node(i.e. starting node of the list) by scanning the whole list
once.Then from the remaining list,again a node with the smallest data is
found out whose address is kept in the 'next' field of previous node(head
node).This process continues to sort the whole list.
2. Function 'void Sort_method2()' - This function uses insertion sort
method(I think).
In this function,starting from second node in the list, all previous node
data(starting from 'head' node) are compared with current reference node
(which is initially second node in the list).If 'data' field of current
reference node is smaller than that of any of its previous nodes,then
suitable changes in the 'next' field of corresponding nodes are made.If
data in the current reference node is smaller than that in the 'head' node,
then the current reference node is made as 'head' node.
*********************************************************************/
#include<stdio.h>
#include<conio.h>
#include<alloc.h>
#include<stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node *head,*head1;
void Create_node(int data);
void display();
void Sort();
void Sort_method2();
void main()
{
int choice,d;
clrscr();
while(1)
{
printf("\n 1.Create new node");
printf("\n 2.Sort in ascending order");
printf("\n 3.Exit");
printf("\nEnter your choice : ");
scanf("%d",&choice);
switch(choice)
{
case 1: printf("\nEnter data :");
scanf("%d",&d);
Create_node(d);
break;
case 2: Sort(); // At a time,we can use any of these two
//Sort_method2(); // functions to sort our single linked list.
break;
case 3: exit(0);
default:exit(0);
}
} // end of while(1)
} // end of main()
//--------------------------------------------
void Create_node(int d)
{
struct node *newnode,*temp;
newnode = (struct node *)malloc(sizeof(struct node));
newnode -> data = d;
newnode -> next = NULL;
if(head == NULL)
head = newnode;
else
{
temp = head;
while(temp -> next != NULL)
temp = temp -> next;
temp -> next = newnode;
} // end of 'else'
} // end of 'Create_node(int d)'
//---------------------------------------------
void display() // Print linked list contents
{
struct node *temp;
printf("\nList contents are :\n");
temp = head;
while(temp != NULL)
{
printf(" Data = %d Address = %u\n",temp->data,temp);
temp = temp->next;
}
printf("\n");
}
//--------------------------------------------
void Sort()
{
struct node *t,*t1,*t2,*t3;
t1 = head;
head1 = head;
if(head == NULL)
printf("\nThe linked list is empty!");
else
{
while( (t2 = t1 -> next) != NULL)
{
while(t2 != NULL)
{
t3 = t2 -> next;
if( t1 -> data > t2 -> data)
{
t2 -> next = t1;
for(t = t1; t -> next != t2;t = t -> next);
t -> next = t3;
t1 = t2; // t1 = Node with smaller data
t2 = t3; // t2 = Node to be compared with t1
} // end of 'if'
else
{
// t1 = t1; // That is,no change in t1.
t2 = t3;
}
} // end of ' while(t2 != NULL)'
if(head == head1) // We want this action only for first pass of
{ // outer while() loop.Only initially, head = head1.
head = t1;
head1 = t1 -> next;
} // end of 'if(head == head1)'
else
{
for(t = head;t -> next != head1; t = t -> next);
t -> next = t1;
head1 = t1 -> next;
} // end of 'else'
t1 = t1 -> next;
} // end of 'while( (t2 = t1 -> next) != NULL)'
display(); // Display the list.
} // end of 'else' of 'if(head == NULL)'
} // end of 'Sort()'
//--------------------------------------------
void Sort_method2()
{
struct node *t,*t1,*t2,*tt;
if(head == NULL)
printf("\nThe linked list is empty!");
else
{
t1 = head -> next;
while(t1 != NULL) // This is i-loop(outer loop).
{
t2 = t1 -> next;
for(t = head; t != t1; t = t -> next) // This is j-loop(inner loop).
{
if(t1->data < t->data)
{
t1 -> next = t;
for(tt=head; tt->next != t1; tt=tt->next); //end of for loop in 'if'
tt -> next = t2;
if(t == head)
head = t1; // There is only one statement in this 'if'.
else // i.e.,'if(t != head)'
{
for(tt=head; tt->next != t; tt=tt->next);
tt -> next = t1;
}
break;
} // end of 'if'
} // end of outer 'for' loop
t1 = t2;
} // end of 'while'
display(); // Display the list.
} // end of 'else' of 'if(head == NULL)'
} // end of 'Sort_method2()'

Reverse every k nodes of a linked list

I am preparing for a technical interview and I am stuck at writing this program to reverse every k nodes of a linked list.
For example
1->2->3->4->5->6 //Linked List
2->1->4->3->6->5 //Output for k=2
EDIT:
Here is my code. I get only 6->5 as output.
struct node* recrev(struct node* noode,int c)
{
struct node* root=noode,*temp,*final,*prev=NULL;
int count=0;
while(root!=NULL && count<c)
{
count++;
temp=root->link;
root->link=prev;
prev=root;
root=temp;
}
if(temp!=NULL)
noode->link=recrev(temp,c);
else
return prev;
}
Any help is appreciated. Thanks.
EDIT: I tried to implement Eran Zimmerman's Algorithm as below.
struct node* rev(struct node* root,int c)
{
struct node* first=root,*prev,*remaining=NULL;
int count=0;
while(first!=NULL && count<c)
{
count++;
prev=first->link;
first->link=remaining;
remaining=first;
first=prev;
}
return remaining;
}
struct node* recc(struct node* root,int c)
{
struct node* final,*temp,*n=root,*t;
int count=0;
while(n!=NULL)
{
count=0;
temp=rev(n,c);
final=temp;
while(n!=NULL && count<c)
{
printf("inside while: %c\n",n->data); // This gets printed only once
if(n->link==NULL) printf("NULL"); //During first iteration itself NULL gets printed
n=n->link;
final=final->link;
count++;
}
}
final->link=NULL;
return final;
}
Yeah, I have never been a fan of recursion, so here is my shot at it using iteration:
public Node reverse(Node head, int k) {
Node st = head;
if(head == null) {
return null;
}
Node newHead = reverseList(st, k);
st = st.next;
while(st != null) {
reverseList(st, k);
st = st.next;
}
return newHead
}
private Node reverseList(Node head, int k) {
Node prev = null;
Node curr = head;
Node next = head.next;
while(next != null && k != 1){
curr.next = prev;
prev = curr;
curr = next;
next = next.next;
--k;
}
curr.next = prev;
// head is the new tail now.
head.next = next;
// tail is the new head now.
return curr;
}
Here is a pseudo code.
temp = main_head = node.alloc ();
while ( !linked_list.is_empty () )
{
push k nodes on stack
head = stack.pop ();
temp->next = head;
temp = head;
while ( !stack.empty () )
{
temp->next = stack.pop ();
temp = temp->next;
}
}
I have made a demo implementation of this code. Pardon for the messy implementation. This will work for any value of k. Each k sized segment is reversed separately in the inner loop and the different segments are linked with each other in the outer loop before entering the inner one. temp traces the last node of the k sized sublist and head holds the next value of the next sublist, and we link them. An explicit stack is used to do the reversal.
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int a;
struct _node *next;
} node_t;
typedef struct _stack {
node_t *arr[128];
int top;
} stack_t;
void stk_init (stack_t *stk)
{
stk->top = -1;
}
void push (stack_t *stk, node_t *val)
{
stk->arr[++(stk->top)] = val;
}
node_t *pop (stack_t *stk)
{
if (stk->top == -1)
return NULL;
return stk->arr[(stk->top)--];
}
int empty (stack_t *stk)
{
return (stk->top == -1);
}
int main (void)
{
stack_t *stk = malloc (sizeof (stack_t));
node_t *head, *main_head, *temp1, *temp;
int i, k, n;
printf ("\nEnter number of list elements: ");
scanf ("%d", &n);
printf ("\nEnter value of k: ");
scanf ("%d", &k);
/* Using dummy head 'main_head' */
main_head = malloc (sizeof (node_t));
main_head->next = NULL;
/* Populate list */
for (i=n; i>0; i--)
{
temp = malloc (sizeof (node_t));
temp->a = i;
temp->next = main_head->next;
main_head->next = temp;
}
/* Show initial list */
printf ("\n");
for (temp = main_head->next; temp != NULL; temp = temp->next)
{
printf ("%d->", temp->a);
}
stk_init (stk);
/* temp1 is used for traversing the list
* temp is used for tracing the revrsed list
* head is used for tracing the sublist of size 'k' local head
* this head value is used to link with the previous
* sublist's tail value, which we get from temp pointer
*/
temp1 = main_head->next;
temp = main_head;
/* reverse process */
while (temp1)
{
for (i=0; (temp1 != NULL) && (i<k); i++)
{
push (stk, temp1);
temp1 = temp1->next;
}
head = pop (stk);
temp->next = head;
temp = head;
while (!empty (stk))
{
temp->next = pop (stk);
if (temp->next == NULL)
break;
temp = temp->next;
}
}
/* Terminate list with NULL . This is necessary as
* for even no of nodes the last temp->next points
* to its previous node after above process
*/
temp->next = NULL;
printf ("\n");
for (temp = main_head->next; temp != NULL; temp = temp->next)
{
printf ("%d->", temp->a);
}
/* free linked list here */
return 0;
}
I like you recursion, although it may be not the best solution. I can see from your code that you think it deep when you design it. You're just one step away from the answer.
Cause: You forget to return the new root node in your recursion case.
if(temp!=NULL)
noode->link=recrev(temp,c);
// You need return the new root node here
// which in this case is prev:
// return prev;
else
return prev;
I would do something like this:
init curr (node pointer) to point to the beginning of the list.
while end of list is not reached (by curr):
- reverse(curr, k)
- advance curr k times
and reverse is a function that reverses the first k elements starting from curr.
this might not be the most elegant or the most efficient implementation, but it works and is quite simple.
to answer regarding the code you added:
you returned prev, which is constantly being advanced. you should return the beginning of the list.
(I'm assuming this is a singly linked list.) You can keep a temporary pointer (lets call it nodek) and advance it k times in a while loop. This will take O(k). Now you have a pointer to the start of the list and to the last element of the sublist. To reverse here, you remove from head which is O(1) and add to nodek which is O(1). Do this for all elements, so this is O(k) again. Now update root to nodek, and run the while loop on nodek again (to get the new position of nodek) and repeat this whole process again. Remember to do any error checking along the way.
This solution will run at O(n) with only O(1) extra space.
The following solution uses extra space for storing pointers,and reverses each chunk of list separately. Finally,the new list is built. When I tested, this seemed to cover the boundary conditions.
template <typename T>
struct Node {
T data;
struct Node<T>* next;
Node() { next=NULL; }
};
template <class T>
void advancePointerToNextChunk(struct Node<T> * & ptr,int & k) {
int count =0;
while(ptr && count <k ) {
ptr=ptr->next;
count ++;
}
k=count;}
/*K-Reverse Linked List */
template <class T>
void kReverseList( struct Node<T> * & head, int k){
int storeK=k,numchunk=0,hcount=0;
queue < struct Node<T> *> headPointerQueue;
queue <struct Node<T> *> tailPointerQueue;
struct Node<T> * tptr,*hptr;
struct Node<T> * ptr=head,*curHead=head,*kReversedHead,*kReversedTail;
while (ptr) {
advancePointerToNextChunk(ptr,storeK);
reverseN(curHead,storeK,kReversedHead,kReversedTail);
numchunk++;
storeK=k;
curHead=ptr;
tailPointerQueue.push(kReversedTail),headPointerQueue.push(kReversedHead);
}
while( !headPointerQueue.empty() || !tailPointerQueue.empty() ) {
if(!headPointerQueue.empty()) {
hcount++;
if(hcount == 1) {
head=headPointerQueue.front();
headPointerQueue.pop();
}
if(!headPointerQueue.empty()) {
hptr=headPointerQueue.front();
headPointerQueue.pop();
}
}
if( !tailPointerQueue.empty() ) {
tptr=tailPointerQueue.front();
tailPointerQueue.pop();
}
tptr->next=hptr;
}
tptr->next=NULL;}
template <class T> void reverseN(struct Node<T> * & head, int k, struct Node<T> * & kReversedHead, structNode<T> * & kReversedTail ) {
struct Node<T> * ptr=head,*tmp;
int count=0;
struct Node<T> *curr=head,*nextNode,*result=NULL;
while(curr && count <k) {
count++;
cout <<"Curr data="<<curr->data<<"\t"<<"count="<<count<<"\n";
nextNode=curr->next;
curr->next=kReversedHead;
kReversedHead=curr;
if(count ==1 ) kReversedTail=kReversedHead;
curr=nextNode;
}}
public class ReverseEveryKNodes<K>
{
private static class Node<K>
{
private K k;
private Node<K> next;
private Node(K k)
{
this.k = k;
}
}
private Node<K> head;
private Node<K> tail;
private int size;
public void insert(K kk)
{
if(head==null)
{
head = new Node<K>(kk);
tail = head;
}
else
{
tail.next = new Node<K>(kk);
tail = tail.next;
}
size++;
}
public void print()
{
Node<K> temp = head;
while(temp!=null)
{
System.out.print(temp.k+"--->");
temp = temp.next;
}
System.out.println("");
}
public void reverse(int k)
{
head = reverseK(head, k);
}
Node<K> reverseK(Node<K> n, int k)
{
if(n==null)return null;
Node<K> next=n, c=n, previous=null;
int count = 0;
while(c!=null && count<k)
{
next=c.next;
c.next=previous;
previous=c;
c=next;
count++;
}
n.next=reverseK(c, k);
return previous;
}
public static void main(String[] args)
{
ReverseEveryKNodes<Integer> r = new ReverseEveryKNodes<Integer>();
r.insert(10);
r.insert(12);
r.insert(13);
r.insert(14);
r.insert(15);
r.insert(16);
r.insert(17);
r.insert(18);
r.print();
r.reverse(3);
r.print();
}
}

Resources