How would you iterate this 2D linked list? - c

How would you iterate this 2D linked list?
typedef struct _NODE
{
char *pszName;
unsigned long ulIntVal;
char *pszString;
struct _NODE *pNext;
struct _NODE *pDown;
} NODE;
I could do something like this..
NODE *pHEad;
while (pHead != NULL) {
printf("%s", pHead->pDown->pszName);
pHead = pHead->pNext;
}
.. but it would only give me the one node under every next node. What if it is another node under that one again? And under that one again? Or if there is a pNext attached to the pDown?

In the simplest case, you could use something like the following recursive function:
void processNode(NODE *current) {
if (current != NULL) {
printf("%s", current->pszName);
processNode(current->pNext);
processNode(current->pDown);
}
}
int main(void) {
NODE *pHead;
/* ... Do something to fill your list ... */
processNode(pHead);
/* ... */
}
Also be aware that this can cause a deep nesting of the function calls depending on your processed list. So if you are on an embedded system with limited stack size or if you are processing huge lists, you might run out of stack. In that case, you should find another approach for the processing.
Note that this will first process the pNext-list and then start with processing the first node of the pDown-list of the last node. So assuming the following structure (to the right is pNext and downwards is pDown):
pHead -> p1 -------> p2
|- p1_1 |- p2_1 -> p2_1_1
\- p1_2 |- p2_2
\- p2_3 -> p2_3_1
it should print the nodes in the following order:
pHead, p1, p2, p2_1, p2_1_1, p2_2, p2_3, p2_3_1, p1_1, p1_2

Look at this answer. Don't be overwhelmed by the amount of the code. I have added enough comments to help you proceed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Node{
char data[100]; // Assume that this linked list will contain only 100 chars of data
struct Node* next;
} NODE;
// Global Variables are bad, but oh well.
NODE* head = NULL;
// Function to create a node
NODE* createNode(char* str)
{
// First allocate memory for struct
NODE* newNode = malloc(sizeof(NODE));
if(newNode == NULL)
{
printf("Unable to create a new node.");
}
else
{
// Use strcpy or strncpy or memcpy instead of doing something like newNode -> data = str, which changes the pointer, but doesn't copy the contents
// That is do not do newNode -> data = "hello" or something
strncpy(newNode -> data, str, strlen(str));
newNode -> next = NULL;
}
return newNode;
}
void addNode(char* str)
{
// Returns a node which contains str, but points to NULL
NODE* newNode = createNode(str);
// If the linked list is empty, then we make this node itself as the first node(or head)
if(head == NULL)
{
head = newNode;
}
// Else if the linked list is not empty, then we add this node at the start of the linked list
else
{
newNode -> next = head;
head = newNode;
}
}
int main()
{
// Example Linked List Generated(say you already have it in some form)
addNode("This");
addNode("Is");
addNode("Linked List");
// Now let's print the linked list
// Temporary NODE pointer ptr is used in order to not mess with the original NODE pointer head.
NODE* ptr = head;
// Traverse through the linked list starting from head and at the same time printing the corresponding data, until ptr is null
// This ptr != NULL check is exactly what you are looking for. This is your way of stopping the traversal of Linked List once you
// are at the end of it. You don't have to know the number of nodes to stop the traversal this way.
while(ptr != NULL)
{
printf("%s ", ptr -> data);
ptr = ptr -> next;
}
}
However note that the output will be printed in reverse order, since in this implementation of linked list we are adding things towards the back. Just try running the program and start reading the program starting from main function. I have made the code into separate functions to make it easier for you to understand. Just run the code first to get a grasp of what's happening.

You can use iteration instead of recursion by adding a queue, too, if you want to avoid the possibility of a stack overflow—though this will use slightly more heap memory, and there is still a risk that you can run out of heap memory if you have a large list or if you're running on a memory-constrained system. The important part is the print_list function at the end; the other stuff is just a (mostly) self-managing queue implementation I've provided:
typedef struct node_queue NodeQueue;
struct node_queue {
NODE *n;
NodeQueue *next;
};
/*
* Add an item to the end of the queue.
*
* If the item could not be added, 0 is returned.
* Otherwise, a nonzero value is returned.
*/
int enqueue(NodeQueue **headp, NodeQueue **endp, NODE *n)
{
NodeQueue *old_end = *endp;
NodeQueue *new_end;
new_end = malloc(sizeof *new_end);
if (new_end == NULL) {
return 0;
}
new_end->n = n;
new_end->next = NULL;
if (old_end != NULL) {
old_end->next = new_end;
}
if (*headp == NULL) {
*headp = new_end;
}
*endp = new_end;
return 1;
}
/*
* Remove an item from the head of the queue,
* storing it in the object that "nret" points to.
*
* If no item is in the queue, 0 is returned.
* Otherwise, a nonzero value is returned.
*/
int dequeue(NodeQueue **headp, NodeQueue **endp, NODE **nret)
{
NodeQueue *old_head = *headp;
NodeQueue *new_head;
if (old_head == NULL) {
return 0;
}
if (nret != NULL) {
*nret = old_head->n;
}
new_head = old_head->next;
free(old_head);
if (new_head == NULL) {
*endp = NULL;
}
*headp = new_head;
return 1;
}
void print_list(NODE *start)
{
NodeQueue *head = NULL;
NodeQueue *end = NULL;
NODE *current;
current = start;
/* Iterate all `pNext` nodes, then pop each `pDown` node and repeat. */
for (;;) {
/* Add the "down" node to the node queue. */
if (current->pDown != NULL) {
if (!enqueue(&head, &end, current->pDown)) {
perror("warning: could not add node to queue");
}
}
printf("%s", current->pszNode);
/*
* Move to the "next" node.
* If there is no next node, get the first "down" node from the queue.
* If there is no "down" node, break the loop to end processing.
*/
current = current->pNext;
if (current == NULL) {
if (!dequeue(&head, &end, &current)) {
break;
}
}
}
}
This will iterate through all pNext items before moving to a pDown item. The following 2-D list will be printed as A B C D E F G H I J K L M N O P Q:
A
|
B--C
|
D--E-----------F
| |
G-----H I-----J
| | | |
K--L M--N O P
|
Q
You can reverse the priority of pDown/pNext in the print_list function by swapping pNext and pDown inside it, so pNext items are added to the queue and pDown items are iterated until exhausted, which will change the order in which the items are printed to A B D C E G K F I O H M Q L J P N unless you change the structure of the list.
You can see an example using both the code above and the first sample 2-D linked list above at https://repl.it/NjyV/1, though I changed the definition of NODE to make the code using its fields a bit simpler.

Related

How to merge and sort two doubly linked lists in C

I am currently working on a project that takes in two text files with data and sorts them into two separate linked lists. My next step is to create a function that takes in those two lists to merge and sort them by ID in increasing order. I have started the implementation but I am stuck and need some guidance on what it is I am doing wrong for the merge sort function. Everything else is working correctly such as sorting each list individually. I just need a way to take in those two lists and merge sort them together in C. Note: I am using the Ubuntu gcc compiler.
struct List *merge_list(struct List *list1, struct List *list2)
{
struct Node *hand1 = list1->head;
struct Node *hand2 = list2->head;
struct Node *tmp1, *tmp2 = NULL;
struct List *list3 = malloc(sizeof(struct List));
while(list1 && list2 != NULL)
{
if(ptr1->id > ptr2->id)
{
ptr1 = list3->head;
ptr1 = ptr1->next;
}
else
{
ptr2 = list3->head;
ptr2 = ptr2->next;
}
}
return list3;
}
Note: Here are my Node and List structs
struct Node {
int id;
char *fname;
char *lname;
char *department;
float gpa;
struct Node *next;
struct Node *prev;
};
struct List {
struct Node *head;
struct Node *tail;
int count;
};
To merge two sorted lists:
while (hand1 && hand2) {
if (hand1->id <= hand2->id) {
tmp = hand1;
hand1 = hand1->next;
} else {
tmp = hand2;
hand2 = hand2->next;
}
insertNode(list3, tmp);
}
// either hand1 or hand2 will have some leftover elements
// they can be added to the back of list by inserting the head
if (hand1)
insertNode(list3, hand1);
else
insertNode(list3, hand2);
I've left it to you to write insertNode(). In order to preserve the sorting of the two lists, it should insert nodes at the end of the list. It should be very easy since you are tracking the tail of the list.
I would initialize the pointers in list3 to NULL and the count to 0, it should make writing insertNode() easier.
You have two doubly linked list and both are sorted and your requirement is to create a function that takes in those two lists to merge and sort them by ID in increasing order. Since both the doubly linked list is already sorted, you don't need to first merge them and then sort but you can merge them in sorted order.
You can do:
struct Node * merge_list(struct Node * head1, struct Node * head2)
{
struct Node* head3 = NULL;
struct Node* p1 = head1;
struct Node* p2 = head2;
struct Node* p3 = NULL;
while (p1 != NULL || p2 != NULL)
{
struct Node * tmp = NULL;
if (p1 == NULL) {
tmp = p2;
p2 = NULL;
} else if (p2 == NULL) {
tmp = p1;
p1 = NULL;
}
if ((p1 != NULL) && (p2 != NULL)) {
if (p1->id < p2->id) {
tmp = p1;
p1 = p1->next;
} else {
tmp = p2;
p2 = p2->next;
}
}
if (head3 == NULL) {
head3 = tmp;
} else {
p3->next = tmp;
tmp->prev = p3;
}
p3 = tmp;
}
return head3;
}
Output:
List 1:
1 3 7
List 2:
2 4 6 8
Merged list:
1 2 3 4 6 7 8
Few points about merge_list() function:
In this merge_list() function I am taking the head pointers of both the list and returning the head pointer of the merged list. But I can see that you have struct List which maintains the head and tail pointer of the lists. So, you need to do the changes accordingly in the function, like the argument and return type will be struct List * type and in the function, you need to take care of merge list tail pointer as well. The core logic is going to be same.
The function merge_list() modify the two list, which are passed as arguments to it, as it resets the next and prev pointers of the lists node in order to merge them. So, after this function call, both the lists passed as arguments to it are no more valid. Set their head and tail pointer to NULL.
If you want both the list, passed as arguments to merge_list(), intact after the merge_list() call then you need to make copy of node while adding to the merged list. For that, you need to allocate memory to tmp and wherever tmp is set to either p1 or p2, instead assign the values to tmp members. Be cautious here, if a member of the structure Node is a pointer to some memory then allocate memory to that tmp member pointer and copy the value.
Hope this helps.

Merging two linked lists at alternate position

I am merging two linked lists and third lists consist of elements at alternate postions but function which will merge is not working
void insert2()
{
//node ptr-pointer of first linked list<br>
//node1 ptr1-pointer of second list<br>
//node2 ptr2 -pointer of the merged linked list
node *ptr=head;
node1 *ptr1=head1;
node2 *ptr2=(node2*)malloc(sizeof(node2));
node *ptr3;
while(ptr!=NULL&&ptr1!=NULL)
{
//Entering the element of first linked list
ptr2->info=ptr->info;
if(head2==NULL)
{
ptr->next=NULL;
head=ptr;
}
else
{
ptr3=head2;
while(ptr3->next!=NULL)
{
ptr3=ptr3->next;
}
ptr3->next=ptr2;
ptr2->next=NULL;
}
//Entering the element of second linked list
ptr2->info=ptr1->info;
while(ptr3->next!=NULL)
{
ptr3=ptr3->next;
}
ptr3->next=ptr2;
ptr2->next=NULL;
}
}
Suppose we are going to add the nodes alternatively in the second list. So the second list will become the new list. The idea is
Keep 2 pointers pointing to current node. Initially the original lists p and q.
While they are not null (both are not null) you store in the next address of both nodes.
Now what will you do? You will point to the next of p to current of q and current of q to next of p.
The current pointers will now be properly changed to the next nodes because they will now be processed.
-------- ----------
| p_curr|------------>| |--------->NULL
|-------| p_next-->|--------|
-------- ----------
| q_curr|------------>| |--------->NULL
|-------| q_next-->|--------|
//After an iteration in the while loop.
-------- ----------
| |----| --> | p_curr| --------->NULL
|-------| _ |______| |--------|
| |
-------- | | ----------
| |_| |------->| q_curr |--------->NULL
|-------| |--------|
The code will be something like this (For more information check link)
void merge(struct node *p, struct node **q)
{
struct node *p_curr = p, *q_curr = *q;
struct node *p_next, *q_next;
// While therre are avialable positions in p
while (p_curr != NULL && q_curr != NULL)
{
// Save next pointers
p_next = p_curr->next;
q_next = q_curr->next;
// Make q_curr as next of p_curr
q_curr->next = p_next; // Change next pointer of q_curr
p_curr->next = q_curr; // Change next pointer of p_curr
// Update current pointers for next iteration
p_curr = p_next;
q_curr = q_next;
}
*q = q_curr; // Update head pointer of second list
}
Creating a third linked list as result
You can do it similar to the previous way. Now what are the changes you nees to have?
Simply you can make a copy of list A and list B and then you pass these as parameters to the list and you will get the third list from the previous function shown above.
But that's quite a primitive solution. You can also build the list in linear time on fly in the function.
struct node * getnode()
{
struct node *temp=(struct node*)malloc(sizeof(struct node));
if(temp==NULL)
{
printf("\n Error in allocation\n");
exit(0);
}
return temp;
}
void merge(struct node *p, struct node *q,struct node **n)
{
struct node *p_curr = p, *q_curr = q;
struct node **store;
struct node *n1;
// While therre are avialable positions in p
while (p_curr != NULL || q_curr != NULL)
{
if (p_curr)
{
if(first)
{
store=&n1;first=0;
}
n1=getnode();
n1->info=p_curr->info;
n1->next = p_curr->next;
n1=n1->next;
p_curr=p_curr->next;
}
if (q_curr)
{
if(first)
{
store=&n1;first=0;
}
n1=getnode();
n1->info=q_curr->info;
n1->next = q_curr->next;
n1=n1->next;
q_curr=q_curr->next;
}
}
*n=*store;
}
Remember in this case the two if statements are checking whether any of them is NULL. If it is the case then add the nodes of other list in the resulting node. store stores the address of the first node. After all we need to point to the head of the third node.
Try this:
NODE * AlternateListMerge(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL; /* destination head ptr */
NODE **ppDst = &pDst; /* ptr to head or prev->next */
NODE *pNode; /* ptr to node */
while(pSrc1 || pSrc2){
if(pSrc1){
pNode = malloc(sizeof(NODE));
pNode->info = pSrc1->info;
pSrc1 = pSrc1->next;
*ppDst = pNode;
ppDst = &pNode->next;
}
if(pSrc2){
pNode = malloc(sizeof(NODE));
pNode->info = pSrc2->info;
pSrc2 = pSrc2->next;
*ppDst = pNode;
ppDst = &pNode->next;
}
}
*ppDst = NULL;
return pDst;
}
or this (less code, a bit more time):
NODE * AlternateListMerge(NODE *pSrc1, NODE *pSrc2)
{
NODE *pDst = NULL; /* destination head ptr */
NODE **ppDst = &pDst; /* ptr to head or prev->next */
NODE *pNode; /* ptr to node */
NODE *pSwap; /* used for swap */
while(pSrc1 || pSrc2){
if(pSrc1){
pNode = malloc(sizeof(NODE));
pNode->info = pSrc1->info;
pSrc1 = pSrc1->next;
*ppDst = pNode;
ppDst = &pNode->next;
}
pSwap = pSrc1;
pSrc1 = pSrc2;
pSrc2 = pSwap;
}
*ppDst = NULL;
return pDst;
}
With no declarations of the types involved, no information about how your lists are initialized, and no details about how you are trying to output the result, I can speak only in generalities. Given that you did say you want to avoid modifying the original lists, however, it is certain that you need to make a copy of each node in each list. Here's one way you could do it:
struct node {
void *data;
struct node *next;
};
#define COPY(from, to, error_label) do { \
to = malloc(sizeof(struct node)); \
if (! to) { \
/* allocation error */ \
goto error_label; \
} \
to->data = from->data; \
to->next = NULL; \
} while (0)
int merge(struct node *head1, struct node *head2, struct node **result) {
struct node dummy = { NULL, NULL };
struct node *merge_tail = dummy;
int node_count = 0;
while (head1 || head2) {
if (head1) {
COPY(head1, merge_tail->next, allocation_error);
head1 = head1->next;
merge_tail = merge_tail->next;
node_count += 1;
}
if (head2) {
COPY(head2, merge_tail->next, allocation_error);
head2 = head2->next;
merge_tail = merge_tail->next;
node_count += 1;
}
}
*result = dummy->next;
return node_count;
allocation_error:
while (dummy->next) {
struct node *temp = dummy->next;
dummy->next = dummy->next->next;
free(temp);
}
return -1;
}
The basic idea is that you walk both input lists at the same time, alternatively copying nodes into the output list from one input and from the other. This particular implementation returns a count of the total number of nodes in the merged list, or -1 on error; the head of the merged list is returned via the third argument. It will not be tripped up if the input lists have different lengths (left over nodes from the longer list are appended at the end), or if either or both input lists are empty. Most of the gory details of copying a node are factored out into the COPY() macro. The dummy node avoids the head of the merged list being a special case.
Any way around, it makes no sense to do any of this if the nodes from which the three lists are built are of different types.

C Function to leave only unique nodes in singly linked list

I'm having an issue: in a function, program needs to compare two nodes and delete one of them if the node values are the same (example: A -> B -> B -> C >>> A -> B -> C). In a few words: it have to leave only unique nodes.
Steps that I've done: created list from data given in data file and it prints out perfectly. Now I'm struggling comparing two nodes.
Steps that I'm thinking of doing: Put two nodes values in two different variables, then comparing those two and if latest node is equal to previous, delete the latest and somehow link previous node to next node. Then the cycle goes all over again.
Question: How do I compare node with further one?
Here's the code that I have right now:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 255
struct node {
int info;
struct node *next;
} *head = NULL;
int create(FILE **data){
char read[LENGTH];
printf("Write data file name: ");
scanf("%s", read);
*data = fopen (read, "r");
if (data == NULL) {
printf("Error reading given file.");
}
return 0;
}
int put_Symbols_into_list(FILE *data) {
struct node *new_node, *current;
char c;
printf("Data given: ");
while (!feof(data)){
new_node = (struct node*)malloc(sizeof (struct node));
c = fscanf(data, "%s", &new_node -> info);
printf("%s ", &new_node -> info);
if (head == NULL){
head = new_node;
current = new_node;
} else {
current -> next = new_node;
current = new_node;
}
}
}
int delete_Same_Symbols() {
}
int main() {
FILE *data;
struct node *n;
create(&data);
put_Symbols_into_list(data);
delete_Same_Symbols();
//display_List(n);
return 0;
}
An efficient way of remove duplicates is the following:
1. Sort the list
2. Run through the list once deleting any adjacent duplicates.
Whether this solution works for you depends on whether your data can be ordered.
Traverse the list from head to end and maintain a Hash table.
For every element,check whether value is in the hash table: if yes, remove the node; else put value in the hash table.
Time Complexity: O(n) on average (assuming that hash table access time is O(1) on average).
I'll give you the function that will remove the duplicates.
Assuming that your code is working fine and that the info is an int value
Note that if info is a string you will need strcmp function instead of head->info == info.
int exist(NODE *head, int info) {
while (head && head->info != info) // strcmp(info,head->info) != 0
head = head->next;
return head->info == info; // strcmp(info,head->info)
}
void removeDuplicates(NODE **phead, int info) {
NODE *tmp = *phead;
while (tmp->info != info) // strcmp(info,head->info) != 0
tmp = tmp->next;
NODE *tmp1 = tmp->next;
tmp->info = tmp1->info; // strcpy(tmp->info,tmp1->info)
tmp->next = tmp1->next;
free(tmp1);
}

doublepointed list C

I wanted to make a list using double pointer and using void as return.
#include<stdio.h>
#include<stdlib.h>
typedef struct list{
int value;
struct list *next;
}*list;
void addnode(struct list **List, int number) {
if(*List == NULL) {
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
} else {
while((*List)->next != NULL) {
(*List) = (*List)->next;
}
*List = (struct list*)malloc(sizeof(struct list*));
(*List)->value = number;
(*List)->next = NULL;
}
}
int main() {
list List1 = NULL;
addnode(&List1, 20);
printf("%d \n", List1->value);
addnode(&List1, 30);
printf("%d \n", List1->value);
printf("%d \n", List1->next->value);
return 0;
}
The first if in addnode is always executed but i want to append the list if its not empty but it seems like it never work. Ill also get segmenation fault because in the last printf it tries to take the next element in the list but its never initialized like i want.
If everthing worked as i wanted i should have printed out
printf("%d\n", List1->value)
20
printf("%d\n", List1->value)
20
printf("%d\n", List1->next->value)
30
The size you are passing to malloc is wrong.
You are allocating a struct list, not a struct list *.
If you are trying to append a new list item, remember (*List)->next will already be NULL on the second call. The malloc following that uses the pointer before the NULL list item (*List) when it should be assigned to the next list item, the one that is NULL, to make it non-NULL ((*List)->next=malloc(struct list);).
Also, your malloc should be using sizeof(struct list), without the *. If you add the *, you're allocating a struct list **. A rule you can use is use one * fewer than the destination type as the sizeof operand. Since your destination is *List, which is of type struct list *, use sizeof(struct list). Alternatively, because your destination is *List, use sizeof **List (use one more * than the destination variable has). This avoids you needing to know the type. It won't matter if List or *List is NULL because the sizeof operation is executed first; pointer dereferencing never occurs since sizeof works on the type of the variable.
Modify your program like this
int addNode(struct list **List, int number)
{
struct list *new, *tmp; // new = create new node, tmp = navigate to last
new = malloc(sizeof(struct list));
if(!new) { //always validate "malloc"
perror("malloc");
exit(1);
}
new -> value = value; // assigning values to new node
new -> next = NULL;
if(!(*list)) { //Check if list is empty or not, plz initialize *list#main() with NULL as like your program. or write seperate function to initialize
*list = new;
return 0; //no need write else condition, bcoz its the first node. and u can directly return
}
tmp = *list;
while(tmp -> next) // To navigate to last node
tmp = tmp -> next;
tmp -> next = new; //creating link to new node
return 0;
}
It's better to write print function seperatly.
int print(struct list **list)
{
struct *current; //current is your current node position
current = *list;
while(current) { //loop till current node addr == NULL
printf("%d\t", current -> value);
current = current -> next;
}
printf("\n");
return 0;
}

Splitting a linked list

Why are the split lists always empty in this program? (It is derived from the code on the Wikipedia page on Linked Lists.)
/*
Example program from wikipedia linked list article
Modified to find nth node and to split the list
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct ns
{
int data;
struct ns *next; /* pointer to next element in list */
} node;
node *list_add(node **p, int i)
{
node *n = (node *)malloc(sizeof(node));
if (n == NULL)
return NULL;
n->next = *p; //* the previous element (*p) now becomes the "next" element */
*p = n; //* add new empty element to the front (head) of the list */
n->data = i;
return *p;
}
void list_print(node *n)
{
int i=0;
if (n == NULL)
{
printf("list is empty\n");
}
while (n != NULL)
{
printf("Value at node #%d = %d\n", i, n->data);
n = n->next;
i++;
}
}
node *list_nth(node *head, int index) {
node *current = head;
node *temp=NULL;
int count = 0; // the index of the node we're currently looking at
while (current != NULL) {
if (count == index)
temp = current;
count++;
current = current->next;
}
return temp;
}
/*
This function is to split a linked list:
Return a list with nodes starting from index 'int ind' and
step the index by 'int step' until the end of list.
*/
node *list_split(node *head, int ind, int step) {
node *current = head;
node *temp=NULL;
int count = ind; // the index of the node we're currently looking at
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
return temp; /* return the final stepped list */
}
int main(void)
{
node *n = NULL, *list1=NULL, *list2=NULL, *list3=NULL, *list4=NULL;
int i;
/* List with 30 nodes */
for(i=0;i<=30;i++){
list_add(&n, i);
}
list_print(n);
/* Get 1th, 5th, 9th, 13th, 18th ... nodes of n etc */
list1 = list_split(n, 1, 4);
list_print(list1);
list2 = list_split(n, 2, 4); /* 2, 6, 10, 14 etc */
list_print(list2);
list3 = list_split(n, 3, 4); /* 3, 7, 11, 15 etc */
list_print(list3);
list3 = list_split(n, 4, 4); /* 4, 8, 12, 16 etc */
list_print(list4);
getch();
return 0;
}
temp = list_nth(current, ind);
while (current != NULL) {
count = count+step;
temp->next = list_nth(head, count);
current = current->next;
}
You are finding the correct item to begin the split at, but look at what happens to temp from then on ... you only ever assign to temp->next.
You need to keep track of both the head of your split list and the tail where you are inserting new items.
The program, actually, has more than one problem.
Indexes are not a native way to address linked list content. Normally, pointers to nodes or iterators (which are disguised pointers to nodes) are used. With indexes, accessing a node has linear complexity (O(n)) instead of constant O(1).
Note that list_nth returns a pointer to a "live" node within a list, not a copy. By assigning to temp->next in list_split, you are rewiring the original list instead of creating a new one (but maybe it's intentional?)
Within list_split, temp is never advanced, so the loop just keeps attaching nodes to the head instead of to the tail.
Due to use of list_nth for finding nodes by iterating through the whole list from the beginning, list_split has quadratic time (O(n**2)) instead of linear time. It's better to rewrite the function to iterate through the list once and copy (or re-attach) required nodes as it passes them, instead of calling list_nth. Or, you can write current = list_nth(current, step).
[EDIT] Forgot to mention. Since you are rewiring the original list, writing list_nth(head, count) is incorrect: it will be travelling the "short-cirquited" list, not the unmodified one.
I also notice that it looks like you are skipping the first record in the list when you are calculating list_nth. Remember is C we normally start counting at zero.
Draw out a Linked List diagram and follow your logic:
[0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9]->...->[10]->[NULL]
Your description of what list_split is supposed to return is pretty clear, but it's not clear what is supposed to happen, if anything, to the original list. Assuming it's not supposed to change:
node *list_split(node *head, int ind, int step) {
node *current = head;
node *newlist=NULL;
node **end = &newlist;
node *temp = list_nth(current, ind);
while (temp != NULL) {
*end = (node *)malloc(sizeof(node));
if (*end == NULL) return NULL;
(*end)->data = temp->data;
end = &((*end)->next);
temp = list_nth(temp, step);
}
return newlist; /* return the final stepped list */
}
(You probably want to factor a list_insert routine out of that that inserts a new
node at a given location. list_add isn't very useful since it always adds to the
beginning of the list.)

Resources