Reverse a doubly linked list - data-structures

Here's my simple linked list program that creates a doubly linked list, and it works.
#include <iostream>
using namespace std;
typedef struct node {
int data;
node *next;
node *prev;
}node;
void printList(node *temp);
int main()
{
node *head;
head = new node;
head->prev = NULL;
node *next = head;
node *prev = head;
node *temp = head;
node *current = head;
//creates 100 nodes, last one points to next
for(int x = 0; x<100; x++)
{
temp->data = x;
current = temp;
temp = new node;
current->next = temp;
temp->prev = current;
temp->next = NULL;
}
//=========================================
printList(head);
//=========== set everything to head ===========
current = head;
prev = head;
//============= reverses linked list ============
while(current->next != NULL)
{
next = current->next; //moves next pointer to next node
current->prev = next; //points current's previous to next node
current = next; //set current pointer to next node
current->next = prev; //set current's next to previous node
prev = current; //move prev node up to current
}
//================================================
printList(head);
cout<<"done";
return 0;
}
void printList(node *temp)
{
while(temp->next != NULL)
{
cout<<temp->data<<'\n';
temp = temp->next;
}
}
Once I add the reverse function though, it hangs. Actually, the function itself works, but in an IDE, when I LOOP it, it prints out all the values, then just hangs(sits there with blinking cursor) and does nothing.
Solution: Got it to work. This is what my function ended up being.
current = head; //set current pointer to head
prev = head; //set previous pointer to head
next = current->next; //moves next pointer to next node
current->next = NULL; //set the next of the header to NULL, because it will actually be the last
//node of reversed list.
current->prev = next; //set previous of the header to the next node.
while(next != NULL)
{
current = next;
next = current->next;
current->prev = next;
current->next = prev;
prev = current;
}

Your reverse algorithm is basically broken.
On the first pass through:
current = head; // Current is pointing at node 0, node0->next is 1 from before
prev = head; // Prev is pointing at node 0
next = current->next; // next is pointing at 1
current->prev = next; // node0->prev is pointing at 1
current = next; // current is pointing at 1
current->next = prev // node1->next is pointing at 0
then next pass
next = current->next // read up there ^^^ node1->next is pointing at 0
... so next goes back to to node 0.
That is not what you meant to do - it causes you to loop around nodes 1 and zero repeatedly, instead of progressing to node 2 and beyond...
Note that you could have easily debugged this if you put this code into the reverse loop:
cout<<"\nStarting iteration"
cout<<"\nNext is at" << next->data
cout<<"\nCurrent is at" << current->data
cout<<"\nCurrent->next is" << current->next->data
etc... doesn't take long to type, reveals all :)
(probably you would cut it down to do 3 instead of 100)
I just did the steps for 3 nodes manually (on paper) to deduce this answer...

Look this simple solution..
Node* Reverse(Node* head)
{
Node * curr=head;
Node * prev=NULL,* nxt=NULL;
while(curr!=NULL)
{
nxt=curr->next;
curr->next=prev;
curr->prev=nxt;
prev=curr;
curr=nxt;
}
return prev;
// Complete this function
// Do not write the main method.
}

Related

Storing words into a hashtable

I have a file that contains English words in a txt file, each word in a new line.
I'm a beginner in C. I'm using a load and unload functions to store all the words into a hashtable (separate chaining) and unload them from memory, but has ran into some problems.
The functions (the code in main.c is correct):
load:
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include "dictionary.h"
#define SIZE 26
typedef struct node
{
char word[LENGTH+1];
struct node *next;
}node;
unsigned int hash_num = 0;
node *hashtable[SIZE]; //26 letters in alphabet
node *head = NULL;
// hashfunction
unsigned int hash(char const *key)
{
unsigned int hash= tolower(key[0]) - 'a';
return hash % SIZE;
}
/**
* Loads dictionary into memory. Returns true if successful else false.
*/
bool load(const char* dictionary)
{
unsigned int hash_index=0;
FILE *fp = fopen(dictionary, "r");
if(fp == NULL)
{
fprintf(stderr, "Couldn't open %s",dictionary);
return false;
}
//dictionary
while(!feof(fp))
{
node *temp = malloc(sizeof(node));
if (temp == NULL)
{
unload();
fclose(fp);
return false;
}
if(fscanf(fp , "%s", temp->word) == 1) //storing word of dictionary in my new_node -> word
{
hash_index = hash(temp->word);
head= hashtable[hash_index]; //head always points to first element of linked list (containting word of dictionary)
temp->next = head;
head = temp;
hash_num++;
}
else //if fscanf couldn't store the word (return 0)
{
free(temp); //free last temp
break;
}
}
fclose(fp);
return true;
}
unload:
bool unload(void)
{
for(int i=0; i<SIZE; i++)
{
if(hashtable[i] != NULL) //if hashtable isn't NULL (has nodes)
{
node *cursor = hashtable[i]; //cursor points at head of individual linked list
while(cursor != NULL) //free them
{
node *temp = cursor;
cursor = cursor->next;
free(temp);
}
}
}
return true;
}
Can anyone tell me if the logic is correct? Whenever I run valgrind it tells me that all my nodes were allocated but just 3 free'd.
total heap usage: 143,094 allocs, 3 frees, 8,014,288 bytes allocated
LEAK SUMMARY:
==15903== definitely lost: 8,013,040 bytes in 143,090 blocks
==15903== indirectly lost: 0 bytes in 0 blocks
==15903== possibly lost: 0 bytes in 0 blocks
When checking the provided source code (missing "dictionary.h"), the main problem is locating in the load() function.
Problem 1 (Main) - the hashtable[] is never updated when adding a new word/node (after computing hash_index = hash(temp->word);).
To store the updated linked-list (managed as reversed), it is
necessary to update the hashtable[hash_index] with the new node
pointer (the allocated temp node).
temp->next = head;
head = temp;
hashtable[hash_index] = head; // update the hashtable[] pointer
hash_num++;
Alternate solution without global variable head.
temp->next = hashtable[hash_index]; //head always points to first element...
hashtable[hash_index] = temp; // update the hashtable[] pointer
hash_num++;
Instead of
temp->next = head;
head = temp;
hash_num++;
Problem 2 (Small) - the hashtable[SIZE] is never initialized.
In the unload() function, in the for-loop, the if-condition
if(hashtable[i] != NULL) assumes that each item of the array is
initialized to NULL.
Add at the beginning the load() function or before calling it, a for-loop to initialize each pointer.
for(int i=0; i<SIZE; i++)
{
hashtable[i] = NULL;
}
Problem 3 (Potential Bug Source) - as suggest by reviewer, the use of head, declared as a global variable node *head = NULL; could be a potential source of bug.
In the load() function, the variable head is used as a temporary
storage but could store value during software run. If a read operation
is performed without a well-known write operation before, the result
could be an unexpected error even if the compilation doesn't detect
error or warning.
The best way is to reduce the number of global variable as much as
possible.
Enhancement (Reverse the linked-list) - because the managed linked-list is adding new items in the front, here is a solution to add new items in the end.
node *first = hashtable[hash_index];
if (first == NULL) {
hashtable[hash_index] = temp;
}
else {
temp->next = NULL; // ending the list
while (first->next!=NULL) {
first = first->next; // loop until last node
}
first->next = temp; // linking to the last node
}
hash_num++;
Instead of
head= hashtable[hash_index]; //head always points to first element ...
temp->next = head;
head = temp;
hash_num++;

How to construct a binary tree using a level order traversal sequence

How to construct a binary tree using a level order traversal sequence, for example from sequence {1,2,3,#,#,4,#,#,5}, we can construct a binary tree like this:
1
/ \
2 3
/
4
\
5
where '#' signifies a path terminator where no node exists below.
Finally I implement Pham Trung's algorithm by c++
struct TreeNode
{
TreeNode *left;
TreeNode *right;
int val;
TreeNode(int x): left(NULL), right(NULL), val(x) {}
};
TreeNode *build_tree(char nodes[], int n)
{
TreeNode *root = new TreeNode(nodes[0] - '0');
queue<TreeNode*> q;
bool is_left = true;
TreeNode *cur = NULL;
q.push(root);
for (int i = 1; i < n; i++) {
TreeNode *node = NULL;
if (nodes[i] != '#') {
node = new TreeNode(nodes[i] - '0');
q.push(node);
}
if (is_left) {
cur = q.front();
q.pop();
cur->left = node;
is_left = false;
} else {
cur->right = node;
is_left = true;
}
}
return root;
}
Assume using array int[]data with 0-based index, we have a simple function to get children:
Left child
int getLeftChild(int index){
if(index*2 + 1 >= data.length)
return -1;// -1 Means out of bound
return data[(index*2) + 1];
}
Right child
int getRightChild(int index){
if(index*2 + 2 >= data.length)
return -1;// -1 Means out of bound
return data[(index*2) + 2];
}
Edit:
Ok, so by maintaining a queue, we can build this binary tree.
We use a queue to maintain those nodes that are not yet processed.
Using a variable count to keep track of the number of children added for the current node.
First, create a root node, assign it as the current node.
So starting from index 1 (index 0 is the root), as the count is 0, we add this node as left child of the current node.
Increase count. If this node is not '#', add it to the queue.
Moving to the next index, the count is 1, so we add this as right child of current node, reset count to 0 and update current node (by assigning the current node as the first element in the queue). If this node is not '#', add it to the queue.
int count = 0;
Queue q = new Queue();
q.add(new Node(data[0]);
Node cur = null;
for(int i = 1; i < data.length; i++){
Node node = new Node(data[i]);
if(count == 0){
cur = q.dequeue();
}
if(count==0){
count++;
cur.leftChild = node;
}else {
count = 0;
cur.rightChild = node;
}
if(data[i] != '#'){
q.enqueue(node);
}
}
class Node{
int data;
Node leftChild, rightChild;
}
Note: this should only work for a binary tree and not BST.
we can build this binary tree from level order traversal by maintaining a queue. Queue is used to maintain those nodes that are not yet processed.
Using a variable count(index variable) to keep track of the number of children added for the current node.
First, create a root node, assign it as the current node. So starting from index 1,
index value is 1 means, we will add the next value as left node.
index value is 2 means we will add the next value as right node and index value 2 means that we have added left and right node, then do the same for the remaining nodes.
if arr value is -1
3.a. if index value is 1,i.e., there is no left node then change the index variable to add right node.
3.b. if index value is 2, i.e, there is no right node then we have repeat this step for the remaining.
static class Node{
int data;
Node left;
Node right;
Node(int d){
data=d;
left=null;
right=null;
}
}
public static Node constBT(int arr[],int n){
Node root=null;
Node curr=null;
int index=0;
Queue<Node> q=new LinkedList<>();
for(int i=0;i<n;i++){
if(root==null){
root=new Node(arr[i]);
q.add(root);
curr=q.peek();
index=1;
}else{
if(arr[i]==-1){
if(index==1)
index=2;
else{
q.remove();
curr=q.peek();
index=1;
}
}
else if(index==1){
curr.left=new Node(arr[i]);
q.add(curr.left);
index=2;
}else if(index==2){
curr.right=new Node(arr[i]);
q.add(curr.right);
q.remove();
curr=q.peek();
index=1;
}
}
}
return root;
}
My approach is similar to Pham Trung yet intutive. We would maintain an array of Nodes of given data instead of using a queue. We would do reverse engineering on BFS using queue. because BFS for a tree is basically its Level Order Traversal (LOT).
It is important to note that we should have the NULL childs of an node for the LOT to be unique and the reconstruction of Tree from LOT to be possible.
In this case LOT : 1,2,3,-1,-1,4,-1,-1,5
where I have used -1 instead of '#' to represent NULLs
And Tree is
1
/ \
2 3
/ \ /
-1 -1 4
/ \
-1 5
Here, we can easily see that when 1 is popped from the BFS queue, it pushed its left child
(2) and right child (3) in the queue. Similary, for 2 it pushed -1 (NULL) for both of its children. And the process is continued.
So, we can follow the following pseudo code to generate the tree rooted at LOT[0]
j = 1
For every node in LOT:
if n<=j: break
if node != NULL:
make LOT[j] left child of node
if n<=j+1: break
make LOT[j+1] right child of node
j <- j+2
Finally, C++ code for the same
Class Declaration and Preorder traversal
class Node{
public:
int val;
Node* lft, *rgt;
Node(int x ):val(x) {lft=rgt=nullptr;}
};
void preorder(Node* root) {
if(!root) return;
cout<<root->val<<" ";
preorder(root->lft);
preorder(root->rgt);
}
Restoring Tree from LOT Logic
int main(){
int arr[] = {1,2,3,-1,-1,4,-1,-1,5};
int n = sizeof(arr)/sizeof(int);
Node* brr[n];
for(int i=0;i<n;i++) {
if(arr[i]==-1) brr[i] = nullptr;
else brr[i] = new Node(arr[i]);
}
for(int i=0,j=1;j<n;i++) {
if(!brr[i]) continue;
brr[i]->lft = brr[j++];
if(j<n) brr[i]->rgt = brr[j++];
}
preorder(brr[0]);
}
Output: 1 2 3 4 5

Reverse alternate elements and append to end of the list

Given a linked list as a->x->b->y->c->z , we need to reverse alternate element and append to end of list. That is , output it as a->b->c->z->y->x.
I have an O(n) solution but it takes extra memory , we take 2 lists and fill it with alternate elements respectively , so the two lists are a b c and x y z and then we will reverse the second list and append it to the tail of first so that it becomes a b c z y x .
My question is can we do it in place ? Or is there any other algorithm for the same ?
The basic idea:
Store x.
Make a point to b.
Make y point to the stored element (x).
Make b point to c.
etc.
At the end, make the last element at an odd position point to the stored element.
Pseudo-code: (simplified end-of-list check for readability)
current = startOfList
stored = NULL
while !endOfList
temp = current.next
current.next = current.next.next
temp.next = stored
stored = temp
current = current.next
current.next = stored
Complexity:
O(n) time, O(1) space.
Here is logic in recursion mode
public static Node alRev(Node head)
{
if (head == null) return head;
if (head.next != null)
{
if (head.next.next != null)
{
Node n = head.next;
head.next = head.next.next;
n.next = null;
Node temp = alRev(head.next);
if (temp != null){
temp.next = n;
return n;
}
}
else
return head.next;
}
else
return head;
return null;
}
This is a recent question from amazon interview, the Idea looks good and there seems to be no trick in it.
Java code with comments:
static void change(Node n)
{
if(n == null)
return;
Node current = n;
Node next = null, prev = null;
while(current != null && current.next != null)
{
// One of the alternate node which is to be reversed.
Node temp = current.next;
current.next = temp.next;
// Reverse the alternate node by changing its next pointer.
temp.next = next;
next = temp;
// This node will be used in the final step
// outside the loop to attach reversed nodes.
prev = current;
current = current.next;
}
// If there are odd number of nodes in the linked list.
if(current != null)
prev = current;
// Attach the reversed list to the unreversed list.
prev.next = next;
}
here the c code which don't uses any extra space for doing this..enjoy and have fun
in case of any doubt feel free to ask
#include<stdio.h>
#include<stdlib.h>
int n;
struct link
{
int val;
struct link *next;
};
void show(struct link *);
void addatbeg(struct link **p,int num)
{
struct link *temp,*help;
help=*p;
temp=(struct link *)malloc(sizeof(struct link));
temp->val=num;
temp->next=NULL;
if(help==NULL)
{
*p=temp;
}
else
{
temp->next=help;
*p=temp;
}
n++;
show(*p);
}
void revapp(struct link **p)
{
struct link *temp,*help,*q,*r;
r=NULL;
temp=*p;
help=*p;
while(temp->next!=NULL)
{
temp=temp->next;
q=r; //this portion will revrse the even position numbers
r=temp;
temp=temp->next;
//for making a connection between odd place numbers
if(help->next->next!=NULL)
{
help->next=temp;
help=help->next;
r->next=q;
}
else
{
r->next=q;
help->next=r;
show(*p);
return;
}
}
}
void show(struct link *q)
{
struct link *temp=q;
printf("\t");
while(q!=NULL )
{
printf("%d ->",q->val);
q=q->next;
if(q==temp)
{
printf("NULL\n");
return;
}
}
printf("NULL\n");
}
int main()
{
n=0;
struct link *p;
p=NULL;
// you can take user defined input but here i am solving it on predefined list
addatbeg(&p,8);
addatbeg(&p,7);
addatbeg(&p,6);
addatbeg(&p,5);
addatbeg(&p,4);
addatbeg(&p,3);
addatbeg(&p,2);
addatbeg(&p,1);
revapp(&p);
return 0;
}`

Implementing the Dutch National Flag Program with Linked Lists

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;
}

Reversing a singly linked list when a block size is given

There is a singly connected linked list and a block size is given.For eg if my linked list is 1->2->3->4->5->6->7->8-NULL and my block size is 4 then reverse the first 4 elements and then the second 4 elements.The output of the problem should be 4->3->2->1->8->7->6->5-NULL
I was thinking of dividing the linked list into segments of size 4 and then reversing it.
But that way I am forced to use a lot of extra nodes which is not desired at all.
The space complexity should be kept to a minimum.
It will be highly appreciable if someone can come with a better solution where the usage of extra nodes would be kept to a minimum.
I tried this...seems to work fine...
node* reverse(node* head) // function to reverse a list
{
node* new_head = NULL;
while(head != NULL)
{
node* next = head->next;
head->next = new_head;
new_head = head;
head = next;
}
return new_head;
}
node* reverse_by_block(node* head, int block)
{
if(head == NULL)
return head;
node* tmp = head;
node* new_head = head;
node* new_tail = NULL;
int count = block;
while(tmp != NULL && count--)
{
new_tail = tmp;
tmp = tmp->next;
}
new_tail->next = NULL;
new_tail = new_head;
new_head = reverse(new_head);
new_tail->next = reverse_by_block(tmp,block);
return new_head;
}
You can advance swapping the current element with the next 3 times: 1234, 2134, 2314, 2341. Then do it twice to get 3421. Then once to get 4321. Then advance 4 steps and repeat the process with the next block.
This can be done in linear-time, with constant space.
Here is a brief description:
Split the linked list into two parts by block-size
int split(node* head, node** listA, node** listB size_t block_size)
{
node* cur = head;
while(block_size && cur)
{
cur = cur->next;
--block_size;
}
if(!cur) { /* error : invalid block size */ return -1; }
*listA = head;
*listB = cur->next;
cur->next = NULL; /* terminate list A */
return 0;
}
Reverse the two sub-parts, (use a non-recursive linear time, constant space function)
reverse(listA);
reverse(listB);
Link them to get the desired linked list.
cur = *listA;
/* goto last but one element of listA */
while(cur->next) cur = cur->next;
cur->next = *listB;

Resources