I try to implement quicksort with partition using linked list. I did it few times with regular array and I got the idea well, but with linked list it is really different. I
did the first part and than I got stuck.
This is the point I stick let say I have an array { 5, 3, 7, 1, 9, 8, 2, 5, 6 }
so the pivot is always the first number - 5;
I build new 2 array one with numbers lower than five (include 5) and another with number bigger than 5 and after that rebuild the main list like that { 3, 1, 2, 5, 5, 7, 9, 8, 6 };
the best result I got until now after 3 runs is 1 -> 2 -> 3 -> 5 -> 5 -> 7 -> 9 -> 8 -> 6;
but because I keeping calling 1 as the partition I get the same result.
I have 2 function partition and quicksort - quicksort need to be recursive function and it my main problem to implement it.
the flag == 1 if array (big/small) isn't empty
my code:
void partition(list **lst, list **pivot, list **small, list **big) {
list *temp = *lst;
list *pv = *lst;
*pivot = pv;
int big_flag = 0;
int small_flag = 0;
*small = (list *)(malloc(sizeof(list)));
list *n_small = *small;
list *prev_small = NULL;
*big = (list *)(malloc(sizeof(list)));
list *n_big = *big;
list *prev_big = NULL;
int p = pv->data;
pv = pv->next;
while (pv) {
if (pv->data <= p) {
n_small->data = pv->data;
prev_small = n_small;
n_small->next = (list *)(malloc(sizeof(list)));
n_small = n_small->next;
small_flag = 1;
} else {
n_big->data = pv->data;
prev_big = n_big;
n_big->next = (list *)(malloc(sizeof(list)));
n_big = n_big->next;
big_flag = 1;
}
pv = pv->next;
}
pv = *lst; // Move the pointer back to the start;
if (small_flag == 1) {
n_small = prev_small;
n_small->next = NULL;
prev_small = *small;
// Built the new lst by order
while (prev_small) {
pv->data = prev_small->data;
pv = pv->next;
prev_small = prev_small->next;
}
}
// add the pivot to the array
pv->data = p;
pv = pv->next;
if (big_flag == 1) {
n_big = prev_big;
n_big->next = NULL;
prev_big = *big;
while (prev_big) {
pv->data = prev_big->data;
pv = pv->next;
prev_big = prev_big->next;
}
}
}
Here I'm really not sure what need to be my stop condition
void quickSortList(list **lst) {
list *temp = *lst;
list *big;
list *small;
list *pivot;
while (temp->next != NULL) {
partition(lst, &pivot, &small, &big);
quickSortList(&small);
quickSortList(&big);
}
}
Quicksort on an array works like this:
do nothing if the array has no or only one element. Otherwise:
pick a pivot and move it out of the way;
partition the array: elements that are less than the pivot go to the left;
put the pivot between the two partitions; this is its final position in the sorted array;
sort the left and right partitions.
This algorithm does not need extra memory. It works in place and all movements are element swaps.
Quicksort on a linked list works like this:
do nothing if the array has no or only one element. Otherwise:
pick a pivot and move it out of the way;
partition the array by moving the elements to one of two new lists, depending on whether the element is less than the pivot or not;
sort the left and right partitions;
concatenate the lists: elements less + pivot + other elements
This algorithm does not need extra memory. It works in place and all movements are adjustments to the head pointers and next field. Only the links change. The nodes stay in their place.
The major difference between these two variants is when you sort the partitions. Array elements are indexed by position, so the position of the partition must be known before sorting, so we place the pivot first.
Linked-list elements are indexed by following the links. The head and tail nodes must be known before sorting, so we must sort first. Then we can concatenate the lists.
So let's write our function:
void quicksort(Node **head);
Wait a moment: Later we need to concatenate linked lists, which means that we need to find the tail of the list. It's a singly linked list, so we must traverse it. We can save some cycles by returning the tail of the sorted list, so:
Node *quicksort(Node **head);
Okay, the base cases first:
if (*head == NULL) return NULL;
if ((*head)->next == NULL) return *head;
We need two lists:
Node *lt = NULL; // less than pivot
Node *ge = NULL; // greater than or equal to pivot
The pivot is the first node, so the *head. The pivot will not be partitioned, so we start partitioning at the node after that:
Node *node = (*head)->next;
We walk the linked list and remove each node. Then we insert that node at the head of one of the two partition lists. (It's easier and faster to insert at the front, but doing so will make the algorithm "unstable", that is the order of two equal elements is not retained. Let's not worry about that right now.)
while (node) {
Node *next = node->next;
if (node->data < (*head)->data) {
node->next = lt;
lt = node;
} else {
node->next = ge;
ge = node;
}
node = next;
}
We must save next to a temporary, because we are overwriting the next field of the node we have just moved.
Now sort the partitions:
Node *ltail = quicksort(<);
Node *gtail = quicksort(&ge);
Nothe that both lt and gt (and therefore ltail and gtail) may be NULL. We have the following lists with {head, tail}:
{lt, ltail} + {pivot, pivot} + {ge, gtail}
The pivot is *head. If ltail is not NULL, ltail->next = pivot and pivot->next = ge, which may be NULL or not. Finally, *head must be the overall new head:
(*head)->next = ge;
if (gtail == NULL) gtail = *head;
if (lt) {
ltail->next = *head;
*head = lt;
}
After this little dance, *head is the new head of the list and gtail is the new tail.
Here's everything put together:
Node *quicksort(Node **head)
{
// base cases: empty list and single node
if (*head == NULL) return NULL;
if ((*head)->next == NULL) return *head;
// partition with *head as pivot
Node *lt = NULL; // less than pivot
Node *ge = NULL; // greater than or equal to pivot
Node *node = (*head)->next;
while (node) {
Node *next = node->next;
if (node->data < (*head)->data) {
node->next = lt;
lt = node;
} else {
node->next = ge;
ge = node;
}
node = next;
}
// quick-sort recursively
Node *ltail = quicksort(<);
Node *gtail = quicksort(&ge);
// rearrange lists: lt -> pivot -> ge
*head = *head;
(*head)->next = ge;
if (gtail == NULL) gtail = *head;
if (lt) {
ltail->next = *head;
*head = lt;
}
return gtail;
}
And here is a complete small example.
Two final remarks: You can make the algorithm stable by inserting at the end of the partition lists. And you don't need two partition lists: You could also extract the nodes that are less from the original list and insert it to the le list. The reiaining elements are the other partition and if you do your extraction right, pivot->next has already the correct value. Memory-wise using just one list won't buy you anything.)
Your implementation has multiple problems:
your quickSortList() function would run forever because you do not update temp in the body of the loop. You should test if the list has at least 3 elements and there is no need for a while loop.
you do not recombine the sublists after recursing, so the sort cannot succeed.
the partition function should not allocate memory, it should merely distribute the nodes into 3 sublists: a list of nodes with smaller data, one with nodes with data equal to the pivot's and one with larger data. Note however that the first and last sublists may be empty.
Here is a full implementation that performs stable sorting, which is possible for linked lists but usually not for arrays as it is more costly.
#include <stdio.h>
#include <stdlib.h>
typedef struct list {
struct list *next;
int data;
} list;
void partition(list **lst, list **pivot, list **small, list **big) {
list *cur = *lst;
list *pivot_head = cur, **pivot_link = &cur->next;
list *small_head = NULL, **small_link = &small_head;
list *big_head = NULL, **big_link = &big_head;
int data = pivot_head->data;
/* distribute the list into 3 sublists */
while ((cur = cur->next) != NULL) {
if (cur->data == data) {
*pivot_link = cur;
pivot_link = &cur->next;
} else
if (cur->data < data) {
*small_link = cur;
small_link = &cur->next;
} else {
*big_link = cur;
big_link = &cur->next;
}
}
/* close the sublists */
*pivot_link = NULL;
*small_link = NULL;
*big_link = NULL;
/* return the sublist heads */
*pivot = pivot_head;
*small = small_head;
*big = big_head;
}
list *appendList(list *a, list *b) {
if (a) {
list *node = a;
while (node->next)
node = node->next;
node->next = b;
return a;
} else {
return b;
}
}
void quickSortList(list **lst) {
list *temp = *lst, *big, *small, *pivot;
if (temp && temp->next) {
partition(lst, &pivot, &small, &big);
quickSortList(&small);
quickSortList(&big);
*lst = appendList(small, appendList(pivot, big));
}
}
list *newList(int data) {
list *node = malloc(sizeof(*node));
node->data = data;
node->next = NULL;
return node;
}
void freeList(list **lst) {
list *cur = *lst;
*lst = NULL;
while (cur) {
list *next = cur->next;
free(cur);
cur = next;
}
}
void printList(const list *node) {
for (; node; node = node->next)
printf(" %d", node->data);
printf("\n");
}
int main() {
list *head = NULL, *tail = NULL, *node;
int p;
while (scanf("%d", &p) == 1) {
node = newList(p);
if (head == NULL) {
tail = head = node;
} else {
tail = tail->next = node;
}
}
printList(head);
quickSortList(&head);
printList(head);
freeList(&head);
return 0;
}
I kept your API for quickSortList and partition but it would be more efficient to keep track of tail nodes everywhere to avoid the extra scan in appendList().
If you can change the API, here is an alternative without extra scans:
/* sort the list and return a pointer to the tail node next pointer */
list **quickSortList(list **lst) {
list *cur = *lst;
if (cur == NULL) {
return NULL;
} else
if (!cur->next) {
return &cur->next;
} else {
list *pivot = cur, **pivot_link = &cur->next;
list *small = NULL, **small_link = &small;
list *big = NULL, **big_link = &big;
int data = pivot->data;
/* distribute the list into 3 sublists */
while ((cur = cur->next) != NULL) {
if (cur->data == data) {
*pivot_link = cur;
pivot_link = &cur->next;
} else
if (cur->data < data) {
*small_link = cur;
small_link = &cur->next;
} else {
*big_link = cur;
big_link = &cur->next;
}
}
*small_link = NULL;
if (small) {
small_link = quickSortList(&small);
*lst = small;
*small_link = pivot;
} else {
*lst = pivot;
}
*big_link = NULL;
if (big) {
big_link = quickSortList(&big);
*pivot_link = big;
return big_link;
} else {
*pivot_link = NULL;
return pivot_link;
}
}
}
Related
I am supposed to make a linked list that takes in strings and prints them out in the reverse order. Normally I'd ask the number of nodes that need to be created, and then ask for the data in a for loop until we're done.
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st *next;
}
But the problem is, the number of nodes isn't known until runtime. So I have to keep asking for data until the user is done. I'm not really sure where to start/how to do that and can't seem to find anything on the internet either. So a hint would be very helpful.
I have my insert function and the print function looks fairly simple too.
word_t *insert_2(word_t* head, string text) {
word_t * p = NULL;
word_t * temp = (word_t*) malloc(sizeof(word_t));
temp -> word = text;
temp -> next = NULL;
if(head == NULL) {
head = temp;
} else {
p = head;
} while(p -> next != NULL) {
p = p -> next;
}
p -> next = temp;
return head;
}
In reverse, replace next by prev:
typedef struct word_st {
string word; // string is meant to be a pointer to a struct
word_st * prev;
}
And the function:
word_t *insert_2(word_t* head, string text) {
word_t * nextHead = (word_t*) malloc(sizeof(word_t));
nextHead -> word = text;
nextHead -> prev = NULL;
// Check first element of LIFO
if( head == NULL ) {
return nextHead;
}
nextHead -> prev = head;
return nextHead;
}
I hope It compiles and work.
Note:
for(word_t * head = last ; head->prev != NULL ; head = head->prev )
{
// Do the job
;
}
I'm trying to implement Shell sort on a linked list. I divide my original linked list into sub linked list, which contain nodes that have 'k' gap regarding the shell sort algorithm. I want to sort the sub linked list by manipulating the 'next' pointers instead of changing its data field. So I have a sortList function that traverses the linked list and swaps the nodes with swapNodes if it encounters any unordered nodes.
When I pass an unordered linked list with two elements to the sortList I keep loosing one of the nodes in my list. For example, I have 50 and -84 in my list, I pass it to sortList. After the sortList figures that they're unordered it calls swapNodes, but once swapNodes terminates, the resulting list only has 50.
I tried to gdb and found out that when I'm in swapNodes scope the list gets sorted successfully without losing a node, but when it terminates and turns back to sortList scope, both the head and curr points only to 50 and their 'next' field is NULL.
My functions:
void sortList(Node * head, long * n_comp) {
Node * curr;
int didSwap = 1;
while(didSwap) {
didSwap = 0;
for(curr = head; curr -> next != NULL; ) {
*n_comp += 1; //number of comparison
if(curr->value > curr->next->value) {
swapNodes(curr, curr->next, &head);
didSwap = 1;
}
curr = curr -> next;
if (!curr) break;
}
}
}
void swapNodes(Node * p1, Node * p2, Node ** start)
{
Node *p1pre = NULL;
Node *p1curr = *start;
while (p1curr && p1curr!=p1)
{
p1pre = p1curr;
p1curr = p1curr->next;
}
Node *p2pre = NULL;
Node *p2curr = *start;
while (p2curr && p2curr != p2)
{
p2pre = p2curr;
p2curr = p2curr->next;
}
if (p1pre != NULL)
{
p1pre->next = p2curr;
}
else
{
*start = p2curr;
}
if (p2pre != NULL)
{
p2pre->next = p1curr;
}
else
{
*start = p1curr;
}
Node *temp = p2curr->next;
p2curr->next = p1curr->next;
p1curr->next = temp;
return;
}
``
It's happening for the same reason why you gave start type Node** in the first place: your node [50] is being moved and head moves with it instead of staying at the start of the list. You need to change your sortList method so the parameter head also has type Node**:
void sortList(Node ** head, long * n_comp) {
Node * curr;
int didSwap = 1;
while(didSwap) {
didSwap = 0;
for(curr = *head; curr -> next != NULL; ) {
std::cout<< "It: " << *n_comp<< std::endl;
*n_comp += 1; //number of comparison
if(curr->value > curr->next->value) {
swapNodes(curr, curr->next, head);
didSwap = 1;
}
curr = curr -> next;
if (!curr) break;
}
}
}
Now your head will stay at the start of the list.
Note: this is one of the reasons why sentinel nodes are a thing.
I want to make a function that can add new elements to double linked list in C, but I couldn't do it. Here is code.
New element should have name, group etc. Just explain me how to make name and rest of it I will do by myself.
#include <stdlib.h>
#include <stdio.h>
#include <locale.h>
#include <string.h>
typedef struct inform
{
char name[20];
char group[20];
char form[20];
int day;
int month;
int year;
int srok;
} INF_BLOK;
typedef struct list_elem
{
INF_BLOK inf;
struct list_elem *next, *prev;
} APTEKA;
APTEKA *head, *tail;
int InputData(INF_BLOK* inf);
int main()
{
return 0;
}
I tried to implement a function that inserts an element based on an given index. Note, that i changed your list_item struct a bit so that it contains a pointer to your data-elements.
Here is the implementation:
/**************************************************************
* Function: insert_index
* Parameters: APTEKA* head, INF_BLOK* data, int index
* Return value: Returns NULL on failure, a pointer to the head
* on success
* Description: Inserts a APTEKA* element based on an given
* index
***************************************************************/
APTEKA* insert_index(APTEKA* head, INF_BLOK* data, int index) {
// Local variable for index
int ind = 1;
APTEKA* new_node = (APTEKA*)malloc(sizeof(APTEKA));
new_node->inf = data;
// Check if head exists, the malloc call was successfull and the index is
// in allowed range
// NOTE: Index for head starts at position 1
if(head && new_node && index) {
// If index is one, set a new head
if(index == 1) {
// The previous node is of course NULL
new_node->prev = NULL;
new_node->next = head->next;
if(head->next)
head->next->prev = new_node;
head->next = new_node;
// In a full implementation you need to free the memory for head and the data field in the
// structure. free(...)
// Return a pointer to the new head of the list
return new_node;
} else {
APTEKA* current_node = head->next;
// Loop through all positions before the desired index
for(; ind < (index - 1); ++ind)
current_node = current_node->next;
new_node->prev = current_node;
new_node->next = current_node->next;
if(current_node->next)
current_node->next->prev = new_node;
current_node->next = new_node;
}
}
else {
// Return NULL on failure
return NULL;
}
// Return an pointer to the head
return head;
}
Explanation:
First the function creates a new node named new_node and sets the pointer of the inf data field to the given parameter. Before actually inserting i basically check for that everything is right.
I then divide into two cases: first one to replace the head (index == 1) and second one is for any other index.
If the head should be replaced i change the dependecies and return a pointer to the newly created node. For any other case i iterate to the element before the index and then try to insert it.
When i tested it with this main function, it seemed to work:
int main()
{
/* Only used for testing purposes */
APTEKA* head = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* first = (APTEKA*)malloc(sizeof(APTEKA));
APTEKA* tail = (APTEKA*)malloc(sizeof(APTEKA));
head->next = first, head->prev = NULL;
first->next = tail, first->prev = head;
tail->next = NULL, tail->prev = first;
/* Information for head node */
INF_BLOK* block_head = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_head->name, "Head", 5);
/* Information for tail node */
INF_BLOK* block_tail = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_tail->name, "Tail", 5);
/* Information for first block */
INF_BLOK* block_first = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_first->name, "First", 6);
/* Information for block to add */
INF_BLOK* block_sec = (INF_BLOK*)malloc(sizeof(INF_BLOK));
memcpy(block_sec->name, "Second", 7);
head->inf = block_head, first->inf = block_first, tail->inf = block_tail;
if(!insert_index(head, block_sec, 2))
fprintf(stderr, "Error inserting element\n");
APTEKA* element = head;
/* Print out name-data of nodes */
while(element) {
puts(element->inf->name);
element = element->next;
}
element = head;
// Freeing everything
while (element) {
APTEKA* next = element->next;
free(element->inf), free(element);
element = next;
}
return 0;
}
Hopefully, my answer gives you the desired insights. If i did something wrong, please correct me :)
NOTE: For this answer i only used the name attribute of your data-item structure. For storing the group, form, etc. you will need another procedure setting those values.
I am trying to create a function splitlist(), which will split a singly linked list into two sublists – one for the front half, and one for the back half. I have come up with a code below which will work for the first time that I call the function, but when I call the function repeatedly, the program crashes. Any advice on how I can change my code to prevent such an error? The function splitlist() is void as it prints two lists which contains frontList and backList.
typedef struct _listnode {
int item;
struct _listnode *next;
} ListNode;
typedef struct _linkedlist {
int size;
ListNode *head;
} LinkedList;
void splitlist(LinkedList* list1, LinkedList * firsthalf, LinkedList *secondhalf)
{
ListNode *cur = list1->head;
ListNode *front = firsthalf->head;
ListNode *back = secondhalf->head;
int totalnodes = list1->size;
int i;
if (totalnodes % 2 != 0) //if odd number of elements, add 1 to make it easier for traversal of list
{
totalnodes = totalnodes + 1;
}
int halfnodes = totalnodes / 2;
{
for (i = 0; i < halfnodes; i++)
{
if (firsthalf->head == NULL) //initialise the head
{
firsthalf->head = malloc(sizeof(ListNode)); //create first node
front = firsthalf->head;
}
else
{
front->next = malloc(sizeof(ListNode));
front = front->next;
}
front->item = cur->item; // insert value from list1 into firsthalf
cur = cur->next; //point to next node in list1
}
front->next = NULL; //last node
for (i = halfnodes; i < totalnodes; i++)
{
if (secondhalf->head == NULL)
{
secondhalf->head = malloc(sizeof(ListNode));
back = secondhalf->head;
}
else
{
back->next = malloc(sizeof(ListNode));
back = back->next;
}
back->item = cur->item;
cur = cur->next;
}
back->next = NULL;
}
}
There are many things wrong with this code. First of all malloc return values are not checked, malloc can fail. And i strongly suspect that because of malloc fail your programm stops. You repeatedly allocate the memory inside the function, but do you free it when you do not need it anymore? Why do yo use malloc at all?
As posted earlier you do not need to.
Please post how the function is called, because it is really unclear how LinkedList* list1, LinkedList * firsthalf, LinkedList *secondhalf are used. Also it is unclear what is the structure of LinkedList is.
why use malloc?It will create a new list.But we want to split the list.
I guess firsthalf and second half are NULL
void splitlist(LinkedList* list1, LinkedList * firsthalf, LinkedList *secondhalf)
{
ListNode *cur = list1->head;
ListNode *front;
int totalnodes = list1->size;
int i;
if (totalnodes % 2 != 0) //if odd number of elements, add 1 to make it easier for traversal of list
{
totalnodes = totalnodes + 1;
}
int halfnodes = totalnodes / 2;
firsthalf->head=list1->head;
front=firsthalf->head;
for(i=0;i<halfnode;i++)
front=front->next;
secondhalf->head=front->next;
front->next=NULL;
}
At first glance I can't see much wrong with your code (assuming the assignment is to create copies of the list nodes in the new half lists), so the error could be in how you call the function, as an exmple, that could be:
LinkedList mainlist= {0};
LinkedList firsthalf= {0}, secondhalf= {0};
//mainlist got filled somehow; we now want to split
firsthalf->List= malloc(sizeof(ListNode));
secondthalf->List= malloc(sizeof(ListNode));
memset(firsthalf->List, 0, sizeof(ListNode));
memset(secondhalf->List, 0, sizeof(ListNode));
splitlist(&mainlist, &firsthalf, &secondhalf);
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.)