I have function called splitList
. The function need to remove nodes from the original list and move it to a new list only if the previous node and the next node are smaller than the current node.
If I understood it ok then a linked list will be in fact split.
- if original list is empty then we will have 2 empty lists
- we have a rule for head node: if it is larger than the 2nd one then i will be moved
- we have a rule for tail node: if it is larger than the previous one then it will be moved
- we have a rule for a single node input list: this node will be moved
About the example and the rules
The example should state formally how should the list be scanned in order to get the expected results. As an example, if the lis is 3 1 9 8 5
as the 1 9 8
trio is scanned the 9
is moved. But now the list has 3 1 8 5
and then the 8
should also go...
About he provided code
Please post something we can compile. A full piece of code.
This is hardly he first linked list related program I believe. So you must have the list implementation fully separated from the code of the problem here.
I will left below a complete example of that. Let us see if it helps
The (provided) Example
We have a 7-node list [ 3 6 1 9 8 4 5 ] that, according to the rules, will be split in a 4-node and a 3-node list with
splitList()
it the target function
I will rename it to split_list()
just because I expected java functions named splitList but C
functions named split_list
precondition: we need a linked list implementation
Today, hours back I posted one here, and since you posted no code for that it is easier to use this one I posted.
Here are the functions for a List
, and the List
itself:
#include <stdio.h>
#include <stdlib.h>
typedef struct s_n
{
int number;
struct s_n* next;
struct s_n* prev;
} Node;
typedef struct
{
unsigned size;
Node* head;
Node* tail;
} List;
List* create();
List* destroy(List* toGo);
int add(int data, List* list);
int delete(int one, List* list);
int display(List* list, const char* title);
Node* find(int one, List* list);
find()
will not be used here. The others work as expected. I believe that you have a similar implementation, or any one. No one is tasked to write a split list function before being tasked to write code for a simple linked list for numbers.
Anyway I will post the complete code at the end.
back to split_list()
This is the prototype:
List* split_list(List* original);
Note that the original list is modified, so the returned List
is not the only result of split_list()
execution.
build_list()
a helper function
This 4-line one helps to create a list in one line
List* builder(unsigned size, int V[])
{
List* nl = create();
if (nl == NULL) return NULL;
for (unsigned i = 0; i < size; i += 1) add(V[i], nl);
return nl;
};
As in this code:
my_list = builder(7, (int[]){3, 6, 1, 9, 8, 4, 5});
That returns the list of the example.
a possible split_list()
List* split_list(List* orig)
{
if (orig == NULL) return NULL;
List* sec = create(); // the new list
// rule 1: if original list is empty then it is done
if (orig->size == 0) return NULL;
// rule 2: if there is a single node on list it is moved
if (orig->size == 1)
{
add(orig->head->number, sec);
delete (orig->head->number, orig);
return sec; // that is all
}
// rule 3: head node
if (orig->head->number > orig->head->next->number)
{
add(orig->head->number, sec);
delete (orig->head->number, orig);
};
// assuming that there is no re-scanning of the list
while (orig->size > 3)
{ // we need at least 3
Node* p = orig->head->next; // the second one
// now we need to compare trios 1-2-3 2-3-4 and so
// on until the last one ends in the tail
// we have 'size' so we need to look
// until the one before the last
char change = 0;
for (unsigned ix = 0; ix < orig->size - 2; ix += 1)
{ // just for readability
int l = p->prev->number;
int c = p->number;
int r = p->next->number;
// so [ l, c, r ] are the numbers
// rule 0 here
if ((c > l) && (c > r))
{ // then move this one, c
add(c, sec);
delete (c, orig); // change in orig
change = 1;
break; // will redefine pointers
};
p = p->next;
};
if (change == 0) break; // no extraction in loop
};
// rule 5: remove tail node if greater than predecessor
Node* p = orig->tail;
if (p->number > p->prev->number)
{
add(p->number, sec);
// the list can have duplicates?
delete_tail(orig);
}
return sec;
}
This one is possibly correct. But for the example it does not return the same values. But are also my view of the application of the rules :)
main.c
for this test
Due to the generic implementation of List
the code is a bit simplistic:
int main(void)
{
List* my_list = NULL;
List* filter = NULL;
my_list = builder(7, (int[]){3, 6, 1, 9, 8, 4, 5});
display(my_list, "\n\t==> Original list set 1");
filter = split_list(my_list);
display(my_list, "\tOriginal items left");
display(filter, "\tExtracted items");
my_list = destroy(my_list);
filter = destroy(filter);
return 0;
}
The lists are declared at the top so we can copy and paste the block below to test for other lists...
output for this test
==> Original list set 1
List size: 7
[ 3 6 1 9 8 4 5 ]
Original items left
List size: 3
[ 3 1 4 ]
Extracted items
List size: 4
[ 6 9 8 5 ]
The sequence as I see is
- move
6
because of sequence 3 6 1
- skips
3 1 9
- move
9
due to 1 9 8
- skips
3 1 8
- move
8
due to 1 8 4
- skips
3 1 4
- skips
1 4 5
- move
5
since it is tail node and greater than 4
So the list is split in:
- `3 1 4` that is left on original list
- `6 9 8 5` that goes to the second one
Complete code for this example
main.c
This file contains also builder()
and split_list()
#include "so_list.h"
List* split_list(List*);
List* builder(unsigned, int[]);
int main(void)
{
List* my_list = NULL;
List* filter = NULL;
my_list = builder(7, (int[]){3, 6, 1, 9, 8, 4, 5});
display(my_list, "\n\t==> Original list set 1");
filter = split_list(my_list);
display(my_list, "\tOriginal items left");
display(filter, "\tExtracted items");
my_list = destroy(my_list);
filter = destroy(filter);
return 0;
}
List* builder(unsigned size, int V[])
{
List* nl = create();
if (nl == NULL) return NULL;
for (unsigned i = 0; i < size; i += 1) add(V[i], nl);
return nl;
};
List* split_list(List* orig)
{
if (orig == NULL) return NULL;
List* sec = create(); // the new list
// rule 1: if original list is empty then it is done
if (orig->size == 0) return NULL;
// rule 2: if there is a single node on list it is moved
if (orig->size == 1)
{
add(orig->head->number, sec);
delete (orig->head->number, orig);
return sec; // that is all
}
// rule 3: head node
if (orig->head->number > orig->head->next->number)
{
add(orig->head->number, sec);
delete (orig->head->number, orig);
};
// assuming that there is no re-scanning of the list
while (orig->size > 3)
{ // we need at least 3
Node* p = orig->head->next; // the second one
// now we need to compare trios 1-2-3 2-3-4 and so
// on until the last one ends in the tail
// we have 'size' so we need to look
// until the one before the last
char change = 0;
for (unsigned ix = 0; ix < orig->size - 2; ix += 1)
{ // just for readability
int l = p->prev->number;
int c = p->number;
int r = p->next->number;
// so [ l, c, r ] are the numbers
// rule 0 here
if ((c > l) && (c > r))
{ // then move this one, c
add(c, sec);
delete (c, orig); // change in orig
change = 1;
break; // will redefine pointers
};
p = p->next;
};
if (change == 0) break; // no extraction in loop
};
// rule 5: remove tail node if greater than predecessor
Node* p = orig->tail;
if (p->number > p->prev->number)
{
add(p->number, sec);
// the list can have duplicates?
delete_tail(orig);
}
return sec;
}
// https://stackoverflow.com/questions/76980148/
// move-node-from-one-linked-list-to-another-in
// -certain-conditions
so_list.h()
header file
#include <stdio.h>
#include <stdlib.h>
typedef struct s_n
{
int number;
struct s_n* next;
struct s_n* prev;
} Node;
typedef struct
{
unsigned size;
Node* head;
Node* tail;
} List;
List* create();
List* destroy(List* toGo);
int add(int data, List* list);
int delete(int one, List* list);
int delete_tail(List* list);
int display(List* list, const char* title);
Node* find(int one, List* list);
so_list.c
: simple implementation for list
#include "so_list.h"
List* create()
{
List* one = malloc(sizeof(List));
if (one == NULL) return NULL;
one->size = 0;
one->head = NULL;
one->tail = NULL;
return one;
}
int delete(int data, List* list)
{ // delete the 1st node that contains 'data'
if (list == NULL) return -1;
if (list->size == 1)
{ // now it is empty
free(list->head);
list->head = list->tail = NULL;
list->size = 0;
return 0; // ok
}
Node* p = list->head; // there are more than 1
for (unsigned i = 0; i < list->size; i += 1)
{
if (p->number == data)
{ // this is the one
if (p == list->head)
{ // delete head element
list->head->next->prev = p->next;
list->head = p->next;
if (list->size == 2) list->tail = list->head;
}
else
{
if (p == list->tail)
{ // delete last
list->tail = p->prev;
p->prev->next = NULL;
if (list->size == 2)
list->head = list->tail;
}
else
{ // p is in the middle of the list
p->prev->next = p->next;
p->next->prev = p->prev;
}
}
list->size -= 1;
free(p);
return 0; // ok
}
p = p->next; // go ahead
}
return -2; // not found
};
List* destroy(List* gone)
{
if (gone == NULL) return NULL;
for (unsigned i = 0; i < gone->size; i += 1)
{
Node* p = gone->head->next;
free(gone->head);
gone->head = p;
}
free(gone);
return NULL;
};
int add(int data, List* list)
{ // insert at last element
if (list == NULL) return -1;
Node* p = malloc(sizeof(Node));
p->number = data; // data copied to node
p->next = NULL; // inserted at tail
if (list->size == 0)
{
list->head = list->tail = p;
list->size = 1;
p->prev = NULL;
return 0;
}
list->tail->next = p;
p->prev = list->tail;
list->tail = p;
list->size += 1; // count it in
return 0;
}
int delete_tail(List* list)
{
if (list == NULL) return -1;
if (list->size == 0) return -2;
if (list->size == 1)
{ // now it is empty
free(list->head);
list->head = list->tail = NULL;
list->size = 0;
return 0; // ok
}
Node* p = list->tail;
list->tail = p->prev;
list->size -= 1;
free(p);
return 0; // ok
}
int display(List* list, const char* title)
{
if (title != NULL) printf("%s", title);
if (list == NULL)
{
printf("\nList does not exist\n");
return 0;
}
printf("\nList size: %u\n [ ", list->size);
Node* p = list->head;
for (unsigned i = 0; i < list->size; i += 1)
{
printf("%d ", p->number);
p = p->next;
}
printf("]\n\n");
return 0;
};
Node* find(int data, List* list)
{ // return address of the first node with 'data'
// or NULL if not found. Do not consider the
// 'list` as sorted
if (list == NULL)
{
fprintf(stderr, "\nfind(): List does not exist\n");
return NULL;
}
Node* p = list->head;
for (unsigned i = 0; i < list->size; i += 1)
{
if (p->number == data) return p;
p = p->next;
}
return NULL;
};
copy vs move a Node
from one list to another
The code here only copy data, even the moved values are copies.
If it is really essencial to move the nodes from one list to another, keep in mind that find()
returns the node address and could be used for a move operation. By the other side, care must be taken with duplicate values in order to move the exact one node and not a clone.
This is the reason why a delete_tail()
must exist: delete()
deletes the first node with the supplied value. It may not be the tail and instead just a node with the same value.
Maybe it would be too much work for a simple exercise that even misses a formal specification