Implementing a queue using array in C - c

I want to implement a queue in C. In particular i want the queue to be dynamically allocated or fixed size based on user preference.
My issue is that I don't want to shift all values every time something is popped, so i essentially keep track of a cursor indicating the start of the queue in an array and length. When user sets the queue to be dynamically allocated, it adds some complexity to that wrapping around and the code becomes messy.
I was curios if I could somehow free just the first element of dynamically allocated memory and whether it would have weird implications for my code.
So I wonder if anyone could tell me whether:
It is possible to free only a part of memory allocated with malloc? (I considered using reallocarray on the ptr+1 and ptr and then calling free on original pointer, but that seems like ub cuz there is probably some info about size of memory allocated stored internally by os)
If i keep on reallocating in this fashion, would my array by the virtue of being contiguous "walk" out of the process memory? (I hope not since i assume OS does some smart mapping and array is not actually contiguous down there, but better to know that for sure)
Because even i find my questions quite confusingly formulated attached are the diagrams illustrating two points above:
-
-

memmove can be used to shift the elements.
This keeps the allocated memory until the program terminates.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define INC 50
typedef struct queue_s queue;
struct queue_s {
size_t size;
size_t used;
int *arr;
};
queue pop ( queue q) {
if ( q.used) {
q.used -= 1;
memmove ( &q.arr[0], &q.arr[1], sizeof *q.arr * q.used);
}
else {
printf ( "queue is empty\n");
}
return q;
}
queue push ( int data, queue q) {
int *temp = NULL;
if ( q.used >= q.size) {
if ( NULL == ( temp = realloc ( q.arr, sizeof *temp * (q.size + INC)))) {
fprintf ( stderr, "problem realloc q.arr");
return q;
}
q.arr = temp;
q.size += INC;
}
q.arr[q.used] = data;
q.used += 1;
return q;
}
void show ( queue q) {
if ( q.used) {
for ( size_t each = 0; each < q.used; ++each) {
if ( each) {
printf ( "->%d", q.arr[each]);
}
else {
printf ( "%d", q.arr[each]);
}
}
}
else {
printf ( "nothing to show\n");
}
printf ( "\n");
}
int main ( void) {
queue qu = { 0, 0, NULL};
qu = push ( 0, qu);
qu = push ( 1, qu);
qu = push ( 2, qu);
qu = push ( 3, qu);
qu = push ( 4, qu);
qu = push ( 5, qu);
qu = push ( 6, qu);
qu = push ( 7, qu);
qu = push ( 8, qu);
qu = push ( 9, qu);
for ( int each = 0; each < 100000; ++each) {
qu = push ( each, qu);
}
printf ( "pushed\n");
for ( int each = 0; each < 100000; ++each) {
qu = pop ( qu);
}
printf ( "popped\n");
show ( qu);
qu = pop ( qu);
show ( qu);
qu = push ( 10, qu);
show ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
show ( qu);
qu = push ( 11, qu);
qu = push ( 12, qu);
show ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
show ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
qu = pop ( qu);
show ( qu);
free ( qu.arr);
return 0;
}

Yes, it is possible to free only a part of the memory allocated with malloc. You can use the realloc() function to resize the allocated memory and then call free() on the original pointer.
No, your array will not "walk" out of the process memory. The OS does smart memory mapping that prevents this from happening.
#include<stdio.h>
#include<stdlib.h>
// A structure to represent a queue
struct Queue {
int front, rear, size;
unsigned capacity;
int* array; };
// function to create a queue of given capacity.
// It initializes size of queue as 0
struct Queue* createQueue(unsigned capacity) {
struct Queue* queue = (struct Queue*) malloc(sizeof(struct Queue));
queue->capacity = capacity; queue->front = queue->size = 0;
queue->rear = capacity - 1; // This is important, see the enqueue
queue->array = (int*) malloc(queue->capacity * sizeof(int));
return queue;
}
// Queue is full when size becomes equal to the capacity
int isFull(struct Queue* queue) {
return (queue->size == queue->capacity);
}
// Queue is empty when size is 0
int isEmpty(struct Queue* queue) {
return (queue->size == 0);
}
// Function to add an item to the queue.
// It changes rear and size
void enqueue(struct Queue* queue, int item) {
if (isFull(queue)) return; queue->rear = (queue->rear + % queue->capacity;
queue->array[queue->rear] = item; queue->size = queue->size + 1;
printf("%d enqueued to queue\n", item);
}
// Function to remove an item from queue.
// It changes front and size
int dequeue(struct Queue* queue) {
if (isEmpty(queue)) return INT_MIN;
int item = queue->array[queue->front];
queue->front = (queue->front + 1)%queue->capacity;
queue->size = queue->size - 1;
return item;
}
// Function to get front of queue
int front(struct Queue* queue) {
if (isEmpty(queue)) return INT_MIN;
return queue->array[queue->front];
}
// Function to get rear of queue
int rear(struct Queue* queue) {
if (isEmpty(queue)) return INT_MIN;
return queue->array[queue->rear];
}
// Driver program to test above functions./
int main() {
struct Queue* queue = createQueue(1000);
enqueue(queue, 10);
enqueue(queue, 20);
enqueue(queue, 30);
enqueue(queue, 40);
printf("%d dequeued from queue\n\n;, dequeue(queue));
printf("Front item is %d\n;, front(queue));
printf("Rear item is %d\n", rear(queue));
return 0;
}

Related

error printing contents of a nested linked list in c

im new to programming and learning data structures at the moment, i am working on a program that takes input from a file in the following format :
*TEAM1
1-player1
2-player2
3-player3
4-player4
5-player5
6-player6
7-player7
8-player8
9-player9
10-player10
11-player11
12-player12
13-player13
14-player14
15-player15
16-player16
17-player17
18-player18
19-player19
20-player20
21-player21
22-player22
*TEAM2
1-player1
2-player2
3-player3
4-player4
5-player5
6-player6
7-player7
8-player8
9-player9
10-player10
11-player11
12-player12
13-player13
14-player14
15-player15
16-player16
17-player17
18-player18
19-player19
20-player20
21-player21
22-player22
23-player23
24-player24
25-player25
im using a nested linked list because I need each team have its own linked list of players, and if there are more than 11 players in the team they will be inserted into a queue for the same team only
these are the linked lists I created:
typedef struct PLAYERS{
int num;
char name [50];
struct PLAYERS* next;
}PLAYERS;
typedef struct QUEUE{
PLAYERS* front;
PLAYERS* rear;
}QUEUE;
typedef struct teamList{
char code [50];
PLAYERS* player;
QUEUE* playerQueue;
struct teamList* next;
}teamList;
my issue Right now is when I try to insert values from the file in the "Player" linked list part of the nested linked list. it seems like it only saves the latest value inserted into it only, that was made clear to me when I tried to print the contents of the player linked list for a specific team and it only printed the last inserted value, which was 11-player11, then when I tried to print the next value in the list the program finished executing with a NULL value, which im assuming means I tried to print the NULL value the list is pointing at.
here are the parts of the code related to this issue:
teamList* MakeEmptyList(teamList* L) {
L = (teamList*)malloc(sizeof(teamList));
if(L == NULL)
printf("Out of memory!\n");
L->player = makePlayer(L->player); ;
L->playerQueue = makeQueue(L->playerQueue);
L->next = NULL;
return L;
}
PLAYERS* makePlayer(PLAYERS* player){
player = (PLAYERS*)malloc(sizeof(PLAYERS));
player->next = NULL;
return player;
}
void readFile(teamList* team){
teamList* temp = team;
FILE *f = fopen("teamsinfo.txt","r");
int i, counter = 1;
char playerName [50];
char teamCode [50];
if(fscanf(f," *%s",teamCode)> 0){
printf("*%s\n", teamCode);
strcpy(temp->code,teamCode);
}
while(!feof(f)){
if(fscanf(f," *%s",teamCode)> 0){
counter = 1;
temp->next = MakeEmptyList(temp->next);
temp =temp->next;
strcpy(temp->code,teamCode);
}
else if(counter<12){
if(fscanf(f," %d-%s",&i,playerName)> 0){
temp->player = insert(playerName,i,temp->player);
temp->player = temp->player->next;
}
counter++;
}
else if(counter >11){
if(fscanf(f," %d-%s",&i,playerName)> 0){
enQueue(temp->playerQueue,playerName,i);
}
}
}
fclose(f);
}
PLAYERS* insert(char x[],int num, PLAYERS* p) {
PLAYERS* temp ;
temp = (PLAYERS*)malloc(sizeof (PLAYERS));
strcpy(temp->name,x);
temp->num = num;
temp->next=p->next;
p->next=temp;
return p;
}
how can this be solved?
Give this a try. It loads and displays the test file.
while ( ! feof ( f)) is almost always wrong. Why is “while( !feof(file) )” always wrong? has an explanation.
This uses while ( fgets (...)) to read the file, line by line.
Then use sscanf to parse the lines.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct PLAYERS {
int num;
char name[50];
struct PLAYERS* next;
} PLAYERS;
typedef struct QUEUE {
PLAYERS* front;
PLAYERS* rear;
} QUEUE;
typedef struct teamList {
char code [50];
PLAYERS* player;
QUEUE* playerQueue;
struct teamList* next;
} teamList;
teamList *readFile ( teamList* team);
PLAYERS* makePlayer ( PLAYERS* player);
QUEUE* makeQueue ( QUEUE* q);
void DeleteTeamList ( teamList* L);
teamList* MakeEmptyList ( teamList* L);
QUEUE *enQueue ( QUEUE* q, char names[], int number);
teamList *insert ( char y[], int num, teamList* p);
void printStrings ( teamList* x);
int main ( void) {
teamList* teams = NULL;
// teams = MakeEmptyList ( teams);
teams = readFile ( teams);
printStrings ( teams);
DeleteTeamList ( teams);
}
teamList *readFile(teamList* team) {
int i = 0;
int counter = 1;
char playerName[50] = "";
char teamCode[50] = "";
char text[100] = "";
teamList* temp = team;
FILE *f = NULL;
if ( NULL != ( f = fopen("teamsinfo.txt","r"))) {
while( fgets ( text, sizeof text, f)) {
if( 1 == sscanf ( text, " *%49s", teamCode)) {
counter = 1;
if ( temp) {
temp->next = MakeEmptyList ( temp->next);
temp = temp->next;
} else {
temp = MakeEmptyList ( temp);
team = temp;
}
strcpy ( temp->code, teamCode);
} else if ( 2 == sscanf ( text, "%d-%s", &i, playerName)) {
if ( counter < 12) {
temp = insert ( playerName, i, temp);
} else if ( counter > 11) {
temp->playerQueue = enQueue ( temp->playerQueue, playerName, i);
}
counter++;
}
}
fclose ( f);
} else {
perror ( "teamsinfo.txt");
}
return team;
}
PLAYERS* makePlayer ( PLAYERS* player) {
player = malloc ( sizeof *player);
player->next = NULL;
return player;
}
QUEUE* makeQueue ( QUEUE* q) {
q = malloc ( sizeof *q);
q->front = q->rear = NULL;
return q;
}
void DeleteTeamList ( teamList* L) {
teamList* P = NULL;
teamList* temp = NULL;
P = L;
while(P != NULL) {
PLAYERS *player = P->player;
while ( player != NULL) {
PLAYERS *hold = player->next;
free ( player);
player = hold;
}
player = P->playerQueue->front;
while ( player != NULL) {
PLAYERS *each = player->next;
free ( player);
player = each;
}
temp = P->next;
free ( P);
P = temp;
}
}
teamList* MakeEmptyList ( teamList* L) {
if(L != NULL) {
DeleteTeamList( L );
}
if ( NULL == ( L = malloc ( sizeof *L))) {
fprintf ( stderr, "problem malloc L\n");
return NULL;
}
L->player = NULL;
L->playerQueue = NULL;
L->next = NULL;
return L;
}
QUEUE *enQueue ( QUEUE* q, char names[], int number) {
QUEUE* temp = q;
if ( ! temp) {
temp = makeQueue ( temp);
}
PLAYERS *player = NULL;
if ( NULL == ( player = calloc ( 1, sizeof *player))) {
fprintf ( stderr, "problem calloc player\n");
return q;
}
strcpy ( player->name, names);
player->num = number;
if ( ! q || ! q->rear) {
temp->front = temp->rear = player;
printf("----------------- %d-%s -----------------------\n"
,temp->rear->num, temp->rear->name);
return temp;
}
player->next = q->rear;
q->rear = player;
printf("----------------- %d-%s -----------------------\n"
,q->rear->num, q->rear->name);
return q;
}
teamList *insert ( char x[], int num, teamList* p) {
PLAYERS* temp;
temp = malloc ( sizeof *temp);
strcpy ( temp->name, x);
temp->num = num;
temp->next = p->player;
p->player = temp;
return p;
}
void printStrings ( teamList* x) {
teamList* p = x;
while ( p != NULL) {
PLAYERS *players = p->player;
while ( players != NULL) {
printf ( "%s\n", p->code);
printf ( "%d-%s\n", players->num, players->name );
players = players->next;
}
p = p->next;
}
printf("\n");
}

An efficient function to check if a singly linked list is a palindrome or not in C [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 months ago.
Improve this question
I came up with a solution that can check if a singly list is a palindrome or not. but the solution is not efficient enough. Please i need a suggestion, thanks in advance.
Here is the code:
int is_palindrome(listint_t **head)
{
listint_t *current, *temp1, *temp2;
int first_elem, second_elem;
if (*head == NULL || (*head)->next == NULL || (*head)->n == (*head)->next->n)
return (1);
current = *head;
first_elem = (*head)->n;
while (current->next->next != NULL)
current = current->next;
second_elem = current->next->n;
if (first_elem == second_elem)
{
temp1 = *head;
*head = (*head)->next;
temp2 = current->next;
current->next = NULL;
free(temp1);
free(temp2);
return (is_palindrome(head));
}
else
return (0);
}
The recursion can work with a pointers to the last half of the list, a pointer to the beginning of the list and a pointer to an integer to capture non-matching data.
One pointer advances to next as the recursion progresses and arrives at the end of the list.
The other pointer advances to next as the recursion returns.
#include <stdio.h>
#include <stdlib.h>
typedef struct list_s list;
struct list_s {
int data;
list *next;
};
list *is_palindrome ( list *forward, list *backward, int *match) {
list *going = forward;
if ( ! going) {
return backward;
}
list *coming = is_palindrome ( forward->next, backward, match);
if ( *match) { // so far data matches
printf ( "compare data: %d %d\n", going->data, coming->data);
*match = ( going->data == coming->data); // 1 matches 0 not matching
}
return coming->next;
}
int main ( void) {
int palindrome = 1;
int items[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 118, 7, 6, 5, 4, 3, 2, 1};
int size = sizeof items / sizeof *items;
list *head = NULL;
for ( int each = 0; each < size; ++each) {
list *element = NULL;
if ( NULL == ( element = malloc ( sizeof *element))) {
fprintf ( stderr, "problem malloc\n");
return 1;
}
element->next = NULL;
element->data = items[each];
if ( head) {
element->next = head;
head = element;
}
else {
head = element;
}
}
list *half = head;
int toggle = 0;
printf ( "list contents:\n");
list *temp = head;
while ( temp) {
toggle = ! toggle;
if ( toggle) {
half = half->next; // alternately advance to middle of list
}
printf ( "%d ", temp->data);
temp = temp->next;
}
printf ( "\n");
is_palindrome ( half, head, &palindrome);
if ( palindrome) {
printf ( "is a palindrone\n");
}
else {
printf ( "is not a palindrone\n");
}
while ( head) {
list *temp = head;
head = head->next;
free ( temp);
}
head = NULL;
return 0;
}

dequeueing function working with 2 queues encounters segfault?

The function below is supposed to dequeue a structure that is made of 2 queues. Each time we dequeue the first queue, its rear needs to become the front of the second queue. Essentially moving the first element in the second queue to the first queue to be its rear. I came up with the algorithm below:
int dequeue(queue* Q1,queue* Q2){
node* temp;
if(Q1->rear=NULL){
return 0;
}
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
if(count>=3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
Q1->rear->next=Q2->front;
Q1->rear=Q1->rear->next;
Q2->front=Q2->front->next;
Q1->rear->next=NULL;
if(Q2->front=NULL){
Q2->rear=NULL;
}
count--;
return 1;
}
}
It gives a segfault at Q1->rear->next=Q2->front;
is there an alternative way to achieve this?
For starters there is a typo in the condition of the if statement
if(Q2->front=NULL){
Q2->rear=NULL;
}
You are using assignment instead of comparison.
There is also a bug in this if statement
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
q1-front after this statement
Q1->front=Q1->front->next;
can be equal to NULL. In this case you need to set also Q1->rare to NULL.
But in any case your approach with the if statements
if(count<3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
count--;
return 1;
}
if(count>=3){
temp=Q1->front;
Q1->front=Q1->front->next;
free(temp);
//...
makes the code less clear and as it occurred error prone.
I would write the function the following way
int dequeue( queue *q1, queue *q2 )
{
int success = q1->front != NULL;
if ( success )
{
if ( q2->front != NULL )
{
q1->rear->next = q2->front;
q1->rear = q1->rear->next;
q2->front = q2->front->next;
if ( q2->front == NULL ) q2->rear = NULL;
q1->rear->next = NULL;
}
node *tmp = q1->front;
q1->front = q1->front->next;
if ( q1->front == NULL ) q1->rear = NULL;
free( tmp );
--count;
}
return success;
}
Pay attention to that it is a bad programming practice when a function depends on a global variable (I mean the variable count). You could avoid such a situation wrapping queues and the variable count in a structure.
Here is a demonstration program that shows the function in action.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int data;
struct node *next;
} node;
typedef struct queue
{
node *front;
node *rear;
} queue;
size_t count;
int dequeue( queue *q1, queue *q2 )
{
int success = q1->front != NULL;
if ( success )
{
if ( q2->front != NULL )
{
q1->rear->next = q2->front;
q1->rear = q1->rear->next;
q2->front = q2->front->next;
if ( q2->front == NULL ) q2->rear = NULL;
q1->rear->next = NULL;
}
node *tmp = q1->front;
q1->front = q1->front->next;
if ( q1->front == NULL ) q1->rear = NULL;
free( tmp );
--count;
}
return success;
}
int push( queue *q, int data )
{
node *new_node = malloc( sizeof( node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = NULL;
if ( q->rear == NULL )
{
q->front = new_node;
}
else
{
q->rear->next = new_node;
}
q->rear = new_node;
++count;
}
return success;
}
int empty( const queue *q )
{
return q->front == NULL;
}
int front( queue *q )
{
return q->front->data;
}
int main( void )
{
queue q1 = { .front = NULL, .rear = NULL };
queue q2 = { .front = NULL, .rear = NULL };
const int N = 10;
for ( int i = 0; i < N; i++ )
{
if ( i < N / 2 ) push( &q1, i );
else push( &q2, i );
}
while ( !empty( &q1 ) )
{
printf( "%d ", front( &q1 ) );
dequeue( &q1, &q2 );
}
putchar( '\n' );
for ( int i = 0; i < N; i++ )
{
if ( i < N / 2 ) push( &q1, i );
else push( &q2, i );
}
while ( !empty( &q1 ) )
{
printf( "%d ", front( &q1 ) );
dequeue( &q1, &q2 );
}
putchar( '\n' );
}
The program output is
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
There are the same code is executed two times to show that the function dequeue works correctly.

unwanted extra element in list and reverse order of the list

Hi to everyone I have this code. I have to create a list from a file of records in which I have columns of data ( position, time, flags). Everything goes fine but when I print it on std output the list has 1 extra element of zeros and the list is back to front. Can someone kindly explain me why?
thanks a lot to everyone!
here is an example of what I get from output:
::(0.0,0.000000000000000,OK)
::(14000.0,314.000023350630840,OK)
::(21000.0,314.000035023289740,OK)
::(736000.0,314.001227515303469,OK)
::(647000.0,314.001079063932764,NOISE)
::(70000.0,314.000116745763364,OK)
::(487000.0,314.000812207375702,OK)
::(81000.0,314.000135099892645,OK)
::(917000.0,314.001529387085043,NOISE)
::(871000.0,314.001452666758723,OK)
::(380000.0,314.000633767941338,OK)
::(578000.0,314.000964003751733,OK)
::(289000.0,314.000481997603799,OK)
::(597000.0,314.000995684957161,OK)
::(480000.0,314.000800553021577,OK)
::(264000.0,314.000440315509820,OK)
::(408000.0,314.000680456580596,OK)
::(603000.0,314.001005693768377,OK)
::(757000.0,314.001262536680713,OK)
::(369000.0,314.000615422503131,OK)
::(458000.0,314.000763851368049,OK)
Here is the code:
typedef enum { NOTORD=0, TIME=1, POSITION=2 } ord_t; //list order: 0 not ordered, 1 ordered by time, 2 ordered by position
typedef enum { OK=0, NOISE=2 } flag_t; //good/bad record
typedef struct elem {
/** position record*/
double position;
/** time record */
double time;
/** flag noise/good */
flag_t flag;
/** pointer to next element */
struct elem * next;
} elem_t;
typedef struct {
/** pointer to headof list */
elem_t * head;
/** nnumber of element in list */
int nelem;
/** indicate the type of order of the list */
ord_t ord;
} lista_t;
lista_t * new_lista ( void ) { //list creation
lista_t * l ;
if ( ( l = malloc (sizeof ( lista_t ) ) ) == NULL ) {
return NULL;
}
l->head = NULL ;
l->nelem = 0 ;
l->ord = NOTORD;
return l;
}
elem_t* leggi_registrazione (FILE* fd) { //read records from file
elem_t * puntolista;
if (!feof(fd))
{
puntolista=malloc(sizeof(elem_t));
fscanf(fd, "%lf", &(puntolista->position));
fscanf(fd, "%lf", &(puntolista->time));
fscanf(fd, "%d", (int *)&(puntolista->flag));
puntolista->next= NULL;
return puntolista;}
else {return NULL;}
}
static void stampa_lista_r ( FILE * f, elem_t * h ) { //list print funct to use in stampa_lista
if ( h == NULL ) {
return ;
}
if ( h->flag == OK ) fprintf(f,"::(%.1f,%.15f,OK)\n",h->position, h- >time);
if ( h->flag == NOISE ) fprintf(f,"::(%.1f,%.15f,NOISE)\n",h->position, h->time);
stampa_lista_r(f, h->next);
}
void stampa_lista ( FILE * f, lista_t * l ) { //list print function
if ( l == NULL ) return ;
if ( l-> head == NULL ) {
fprintf(stdout,"Lista vuota.\n");
return ;
}
stampa_lista_r (f,l->head);
putchar('\n');
return ;
}
int inserisci ( lista_t * l , elem_t* pelem) { //element insert in list
elem_t *prec;
elem_t *corr;
elem_t *aux;
int trovato = 0;
if (l->ord==NOTORD) //not ordered list
{
//insert at the beginning
aux = malloc(sizeof(elem_t));
aux->position = pelem->position;
aux->time = pelem->time;
aux->flag = pelem->flag;
aux->next = l->head;
l->head = aux;
return 0;
}
if (l->ord==TIME) //time ordered list
{
prec=malloc(sizeof(elem_t));
corr=malloc(sizeof(elem_t));
prec = l->head;
corr = prec -> next;
trovato = 0;
while (corr !=NULL && !trovato)
{
if ((corr -> time) >= (pelem->time))
trovato = 1;
else
{prec = prec -> next;
corr = corr -> next;}
}
aux = malloc(sizeof(elem_t)); //alloc and insert in list
aux->position = (pelem->position);
aux->time = (pelem->time);
aux->flag = (pelem->flag);
prec -> next = aux;
aux -> next = corr;
return 0;
}
if (l->ord==POSITION) //position ordered list
{
prec=malloc(sizeof(elem_t));
corr=malloc(sizeof(elem_t));
prec = l->head;
corr = prec -> next;
trovato = 0;
while (corr !=NULL && !trovato)
{
if ((corr -> position) >= (pelem->position))
trovato = 1;
else
{prec = prec -> next;
corr = corr -> next;}
}
aux = malloc(sizeof(elem_t)); //alloc and insert in list
aux->position = (pelem->position);
aux->time = (pelem->time);
aux->flag = (pelem->flag);
prec -> next = aux;
aux -> next = corr;
return 0;
}
else return -1;
}
int main (void)
{
FILE* f; // pointer to record file
lista_t * ll;
elem_t* pelem;
int err;
char buf[N+2];
f = fopen (FILE1,"r");
if ( f == NULL ) {
perror("fopen");
exit(EXIT_FAILURE);
}
/* delete first line in external file(it's a comment) */
if ( fgets(buf,N+2,f) == NULL ) exit(EXIT_FAILURE);
if (buf[0] != '#') exit(EXIT_FAILURE);
/* read records and insert in new list */
ll = new_lista();
while ( ( pelem = leggi_registrazione(f) ) != NULL ) {
/* insert in list in reading order */
err = inserisci (ll,pelem);
if ( err == -1 ) return EXIT_FAILURE;
}
/* results print */
stampa_lista(stdout,ll) ;
return 0;}

Rename a list with value of another one

I try to implement a program written in C language where I've got two linked list and I need to create a third one in which there are all the values of the first list eventually renamed with the values of the second one based on them order. Any of the value in updated third list should not repeat ,it should return error.
Look at the example given below to understand how this program works:
Ex.1
A = [a, b, c, d]
B = [e, f]
The third one will be:
C = [e, f, c, d]
Ex.2
A = [a, b, c, d]
B = [a, e]
The third one will be:
C = [a, e, c, d]
Ex.3
A = [a, b, c, d]
B = [c, d]
This should return an error because C will be
C = [c, d c, d]
but it can't have duplicate values.
Ex.4
A = [a, b, c, d]
B = [b, a]
This shouldn't return any error because C will be
C = [b, a, c, d]
(there are not duplicate values and the first two elements of the list A will be renamed with the first two elements of the list B).
Below you can find how my idea looks like but I'm interested about different solutions of this problem
T //Temp
C //Result
for (int i = 0; i < |A|; i++)
{
if(i > length of B && T is not empty)
{
//One or more elements were not been renamed
return ERROR
}
if(A[i] == B[i])
{
C[i] = B[i];
}
else
{
C[i] = B[i];
if(T contains A[i])
{
pop A[i] from T
}
else
{
push A[i] in T
}
}
}
EDIT
Background: this algorithm supports the creation of an alias table (C) from a concrete table (A) given a list of filed names (B).
each list/table cannot contain duplicate values.
length of B is less or equal than length of A (I can't rename more values of those I've got)
This could be easily done in Python. Something like this:
def merge_lists(list1, list2):
if len(list2) > len(list1):
raise ValueError("list2 cannot be of greater length than list1")
list3 = list(list1) # make copy of list1
list_after_overlap = list1[len(list2):] # get slice of list1 starting from end of list2
index = 0
for item in list2:
if item not in list_after_overlap:
list3[index] = item
else:
raise ValueError("merged list would have repeated values")
index += 1
return list3
This isn't just Python showing off, although it is arguably a better tool for this job. This also reads nicely like pseudo-code, and having prototyped and tested our algorithm, we can implement the same logic in C, we just need some helper functions.
As it's been indicated, a simple array would do, and since you haven't specified the data type in your question, we'll use a plain old int:
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
result.merged_list.list_length = 0;
result.merged_list.values = NULL;
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
result.merged_list.values = (int*)malloc(sizeof(int)*(list1.list_length));
result.error = (result.merged_list.values == NULL) ? ERROR_MEMORY : ERROR_NONE;
}
if (result.error == ERROR_NONE)
{
replicate_list(&result.merged_list, list1, list2.list_length);
list_t list_after_overlap = get_list_slice(list1, list2.list_length);
for (size_t index = 0; index < list2.list_length && result.error == ERROR_NONE; index++)
{
if (!item_in_list(list2.values[index], list_after_overlap))
{
result.merged_list.values[index] = list2.values[index];
}
else
{
result.error = ERROR_REPEATED_VALUES;
free(result.merged_list.values); /* we won't be needing this anymore */
result.merged_list.values = NULL;
result.merged_list.list_length = 0;
}
}
}
return result;
}
As you can see, the algorithm is essentially the same, with an improvement. In the python code we were copying the entire list1, only to then overwrite the overlapped values, which is a waste that could be meaningful on large lists. Now we only get the part after the overlap, which starts after list2, and use it for testing for duplicates. Here is the complete code, with a hack on main for some basic testing:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
typedef enum {
ERROR_NONE, /* success */
ERROR_REPEATED_VALUES, /* merged list would have repeated values */
ERROR_LENGTH_EXCEEDED, /* second list length exceeds that of first list */
ERROR_MEMORY /* could not allocate memory for the merged list */
} error_t;
typedef struct {
int *values; /* pointer to int array that contains the list values */
size_t list_length; /* the number of elements in the list (array) */
}list_t;
typedef struct {
list_t merged_list; /* has pointer (values) to merged list (array), which MUST be freed */
error_t error; /* indicates success or the error code of the merge operation */
}merged_list_t;
typedef enum {FALSE=0, TRUE=1} bool_t; /* use stdbool.h preferably, if available */
/* === Test Utility functions */
static void print_list(const list_t list)
{
putchar('[');
for (size_t index = 0; index < list.list_length; index++)
{
printf("%d", list.values[index]);
if (index < list.list_length - 1)
{
printf(", ");
}
}
printf("]\n");
}
static void print_merged_list(const merged_list_t list)
{
if (list.merged_list.values != NULL && list.error == ERROR_NONE)
{
print_list(list.merged_list);
}
else
{
switch (list.error)
{
case ERROR_NONE: printf("Merged list is null (empty)\n"); break;
case ERROR_LENGTH_EXCEEDED: printf("Error: Length of list2 is greater than length of list1\n"); break;
case ERROR_MEMORY: printf("Error: Unable to allocate memory for result\n"); break;
case ERROR_REPEATED_VALUES: printf("Error: Merged list would have duplicate entries\n"); break;
default: printf("Unexpected or unhandled error\n"); break;
}
}
}
/* utility functions */
static void replicate_list(list_t *new_list, const list_t list, size_t start)
{
for (size_t index = start; index < list.list_length; index++)
{
new_list->values[index] = list.values[index];
}
new_list->list_length = list.list_length;
}
static list_t get_list_slice(const list_t list, size_t start_index)
{
list_t sliced_list;
if (list.values != NULL && start_index < list.list_length)
{
sliced_list.values = list.values + start_index;
sliced_list.list_length = list.list_length - start_index;
}
return sliced_list;
}
static bool_t item_in_list(int item, const list_t list)
{
bool_t in_list = FALSE;
for (size_t i=0; i < list.list_length && !in_list; i++)
{
in_list = (item == list.values[i]) ? TRUE : FALSE;
}
return in_list;
}
/*
Produces a merged list which consists of list1 replaced by the overlapping elements of list2,
as long as the resulting list does not cause elements of the merged list to be repeated.
Input:
list1[]: int array of arbitrary length consisting of unique elements
list2[]: int array of length smaller than of list1 consisting of unique elements
Returns:
A merged_list_t structure containing the merged list structure (which MUST be freed) and its length
or an error code if the lists are of invalid length or the merge operation produces duplicate values
*/
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
result.merged_list.list_length = 0;
result.merged_list.values = NULL;
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
result.merged_list.values = (int*)malloc(sizeof(int)*(list1.list_length));
result.error = (result.merged_list.values == NULL) ? ERROR_MEMORY : ERROR_NONE;
}
if (result.error == ERROR_NONE)
{
replicate_list(&result.merged_list, list1, list2.list_length);
list_t list_after_overlap = get_list_slice(list1, list2.list_length);
for (size_t index = 0; index < list2.list_length && result.error == ERROR_NONE; index++)
{
if (!item_in_list(list2.values[index], list_after_overlap))
{
result.merged_list.values[index] = list2.values[index];
}
else
{
result.error = ERROR_REPEATED_VALUES;
free(result.merged_list.values); /* we won't be needing this anymore */
result.merged_list.values = NULL;
result.merged_list.list_length = 0;
}
}
}
return result;
}
void main(void)
{
printf("Testing basic scenario\n");
int a1[] = { 1, 2, 3, 4, 5 };
int a2[] = { 6, 7 };
list_t l1;
l1.list_length = sizeof(a1) / sizeof(a1[0]); /* get number of elements */
l1.values = a1;
list_t l2;
l2.list_length = sizeof(a2) / sizeof(a2[0]);
l2.values = a2;
merged_list_t ml = merge_lists(l1, l2);
print_list(l1);
print_list(l2);
print_merged_list(ml);
free(ml.merged_list.values);
printf("Testing merge with duplicate values\n");
int a3[] = { 1, 2, 3, 4, 5 };
int a4[] = { 4, 6, 8 };
list_t l3;
l3.list_length = sizeof(a3) / sizeof(a3[0]); /* get number of elements */
l3.values = a3;
list_t l4;
l4.list_length = sizeof(a4) / sizeof(a4[0]);
l4.values = a4;
merged_list_t ml2 = merge_lists(l3, l4);
print_list(l3);
print_list(l4);
print_merged_list(ml2);
free(ml2.merged_list.values);
printf("Testing list2 with value from list1\n");
int a5[] = { 1, 2, 3, 4, 5 };
int a6[] = { 3, 6, 9 };
list_t l5;
l5.list_length = sizeof(a5) / sizeof(a5[0]); /* get number of elements */
l5.values = a5;
list_t l6;
l6.list_length = sizeof(a6) / sizeof(a6[0]);
l6.values = a6;
merged_list_t ml3 = merge_lists(l5, l6);
print_list(l5);
print_list(l6);
print_merged_list(ml3);
free(ml3.merged_list.values);
_getch();
}
But you specifically asked for linked lists, so to finally answer your question, here is one way to do it:
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
list_t list_after_overlap;
initialize_list(&result.merged_list);
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
bool_t success = replicate_list(&list_after_overlap, list1, list2.list_length);
result.error = (success) ? ERROR_NONE: ERROR_MEMORY;
}
if (result.error == ERROR_NONE)
{
for (list_item_t *item = list2.head; item != NULL && result.error == ERROR_NONE; item = item->next)
{
if (!item_in_list(*item->value, list_after_overlap))
{
/* duplicate each item and append to merged_list */
bool_t success = append_list_item(&result.merged_list, new_list_item(*item->value));
result.error = success ? ERROR_NONE : ERROR_MEMORY;
}
else
{
result.error = ERROR_REPEATED_VALUES;
destroy_list(&list_after_overlap);
destroy_list(&result.merged_list);
}
}
}
if (result.error == ERROR_NONE)
{
/* join overlap with difference */
result.merged_list.tail->next = list_after_overlap.head;
list_after_overlap.head = result.merged_list.head;
result.merged_list.tail = list_after_overlap.tail;
}
return result;
}
Again, same logic, the merge function and friends were just refactored to deal with linked lists. Here is the full code:
/* Enable debug heap functions (Visual Studio) */
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#include <stdio.h>
#include <conio.h>
typedef enum {
ERROR_NONE, /* success */
ERROR_REPEATED_VALUES, /* merged list would have repeated values */
ERROR_LENGTH_EXCEEDED, /* second list length exceeds that of first list */
ERROR_MEMORY /* could not allocate memory for the merged list */
} error_t;
typedef struct list_item_ {
int *value; /* pointer to single value */
list_item_ *next;
list_item_ *previous;
}list_item_t;
typedef struct {
list_item_t *head;
list_item_t *tail;
size_t list_length;
}list_t;
typedef struct {
list_t merged_list; /* linked list with result, MUST be freed */
error_t error; /* indicates success or the error code of the merge operation */
}merged_list_t;
typedef enum {FALSE=0, TRUE=1} bool_t;
/* === Test Utility functions === */
static void print_list(const list_t list)
{
putchar('[');
for (list_item_t *item = list.head; item != NULL; item = item->next)
{
printf("%d", *item->value);
if (item->next != NULL)
{
printf(", "); /* add comma if it's not the last item (tail) */
}
}
printf("]\n");
}
static void print_merged_list(const merged_list_t list)
{
if (list.merged_list.head != NULL && list.error == ERROR_NONE)
{
print_list(list.merged_list);
}
else
{
switch (list.error)
{
case ERROR_NONE: printf("Merged list head is null (empty list)\n"); break;
case ERROR_LENGTH_EXCEEDED: printf("Error: Length of list2 is greater than length of list1\n"); break;
case ERROR_MEMORY: printf("Error: Unable to allocate memory for result\n"); break;
case ERROR_REPEATED_VALUES: printf("Error: Merged list would have duplicate entries\n"); break;
default: printf("Unexpected or unhandled error\n"); break;
}
}
}
/* helper functions */
static void initialize_list(list_t *list)
{
list->head = NULL;
list->tail = NULL;
list->list_length = 0;
}
static list_item_t* new_list_item(int value)
{
list_item_t *item = (list_item_t*)malloc(sizeof(list_item_t));
if (item != NULL)
{
item->value = (int*)malloc(sizeof(int));
if (item->value != NULL)
{
*item->value = value;
item->next = NULL;
item->previous = NULL;
}
else
{
free(item);
item = NULL;
}
}
return item;
}
static bool_t append_list_item(list_t *list, list_item_t *item)
{
bool_t success = TRUE;
if (item == NULL)
{
success = FALSE;
}
else
{
if (list->head == NULL)
{
/* first item, set as head and tail */
list->head = item;
list->head->next = NULL;
list->head->previous = NULL;
list->tail = item;
}
else
{
/* item (new tail) will be preceded by the current tail */
item->previous = list->tail;
/* link current tail to new item */
list->tail->next = item;
/* make item the new tail */
list->tail = item;
list->tail->next = NULL;
}
list->list_length++;
}
return success;
}
static bool_t set_list_values(list_t *list, const int *values, size_t values_length)
{
bool_t success = TRUE;
initialize_list(list);
for (size_t index = 0; index < values_length && success; index++)
{
list_item_t *item = new_list_item(values[index]);
success = append_list_item(list, item);
}
if (success)
{
list->list_length = values_length;
}
return success;
}
static void destroy_list(list_t *list)
{
list_item_t *next_item = NULL;
for (list_item_t *item = list->head; item != NULL; item = next_item)
{
next_item = item->next;
free(item->value);
item->value = NULL;
free(item);
item = NULL;
}
list->list_length = 0;
list->head = NULL;
list->tail = NULL;
}
static bool_t replicate_list(list_t *new_list, const list_t list, const size_t start)
{
size_t count = 0;
list_item_t *item;
bool_t success = TRUE;
initialize_list(new_list);
for (item = list.head; item != NULL && success; item = item->next, count++)
{
/* skip items before start */
if (count >= start)
{
/* create new list with remaining items */
success = append_list_item(new_list, new_list_item(*item->value));
}
}
if (!success)
{
destroy_list(new_list);
}
return success;
}
static bool_t item_in_list(int item, const list_t list)
{
bool_t in_list = FALSE;
for (list_item_t *l_item = list.head; (l_item != NULL) && !in_list; l_item = l_item->next)
{
in_list = (item == *l_item->value) ? TRUE : FALSE;
}
return in_list;
}
/*
Produces a merged list which consists of list1 replaced by the overlapping elements of list2,
as long as the resulting list does not cause elements of the merged list to be repeated.
Input:
list1[]: a linked list of arbitrary length consisting of unique elements
list2[]: a linked list of length less than or equal to the length of list 1, also with unique elements
Returns:
A merged_list_t structure containing the merged linked list (which MUST be freed) and its length
or an error code if the lists are of invalid length or the merge operation produces duplicate values
*/
merged_list_t merge_lists(const list_t list1, const list_t list2)
{
merged_list_t result;
list_t list_after_overlap;
initialize_list(&result.merged_list);
if (list2.list_length > list1.list_length)
{
result.error = ERROR_LENGTH_EXCEEDED;
}
else
{
bool_t success = replicate_list(&list_after_overlap, list1, list2.list_length);
result.error = (success) ? ERROR_NONE: ERROR_MEMORY;
}
if (result.error == ERROR_NONE)
{
for (list_item_t *item = list2.head; item != NULL && result.error == ERROR_NONE; item = item->next)
{
if (!item_in_list(*item->value, list_after_overlap))
{
/* duplicate each item and append to merged_list */
bool_t success = append_list_item(&result.merged_list, new_list_item(*item->value));
result.error = success ? ERROR_NONE : ERROR_MEMORY;
}
else
{
result.error = ERROR_REPEATED_VALUES;
destroy_list(&list_after_overlap);
destroy_list(&result.merged_list);
}
}
}
if (result.error == ERROR_NONE)
{
/* join overlap with difference */
result.merged_list.tail->next = list_after_overlap.head;
list_after_overlap.head = result.merged_list.head;
result.merged_list.tail = list_after_overlap.tail;
}
return result;
}
void main(void)
{
printf("Testing basic scenario\n");
int a1[] = { 1, 2, 3, 4, 5 };
int a2[] = { 6, 7 };
list_t l1;
set_list_values(&l1, a1, sizeof(a1) / sizeof(a1[0]));
list_t l2;
set_list_values(&l2, a2, sizeof(a2) / sizeof(a2[0]));
print_list(l1);
print_list(l2);
merged_list_t ml = merge_lists(l1, l2);
print_merged_list(ml);
destroy_list(&l1);
destroy_list(&l2);
destroy_list(&ml.merged_list);
printf("Testing merge with duplicate values\n");
int a3[] = { 1, 2, 3, 4, 5 };
int a4[] = { 4, 6, 8 };
list_t l3;
set_list_values(&l3, a3, sizeof(a3) / sizeof(a3[0]));
list_t l4;
set_list_values(&l4, a4, sizeof(a4) / sizeof(a4[0]));
print_list(l3);
print_list(l4);
ml = merge_lists(l3, l4);
print_merged_list(ml);
destroy_list(&l3);
destroy_list(&l4);
destroy_list(&ml.merged_list);
printf("Testing list2 with value from list1\n");
int a5[] = { 1, 2, 3, 4, 5 };
int a6[] = { 3, 6, 9 };
list_t l5;
set_list_values(&l5, a5, sizeof(a5) / sizeof(a5[0]));
list_t l6;
set_list_values(&l6, a6, sizeof(a6) / sizeof(a6[0]));
print_list(l5);
print_list(l6);
ml = merge_lists(l5, l6);
print_merged_list(ml);
destroy_list(&l5);
destroy_list(&l6);
destroy_list(&ml.merged_list);
printf("Try printing empty list...\n");
print_merged_list(ml);
/* print memory leak report (Visual Studio)*/
_CrtDumpMemoryLeaks();
_getch();
}
Notice the _CrtDumpMemoryLeaks() macro if you are using Visual Studio, very handy for detecting memory leaks. Of course, if you are lucky to be running Linux just get rid of that and use Valgrind instead. On my system, it was clean.
Here is a sample of the output produced by main:
Testing basic scenario
[1, 2, 3, 4, 5]
[6, 7]
[6, 7, 3, 4, 5]
Testing merge with duplicate values
[1, 2, 3, 4, 5]
[4, 6, 8]
Error: Merged list would have duplicate entries
Testing list2 with value from list1
[1, 2, 3, 4, 5]
[3, 6, 9]
[3, 6, 9, 4, 5]
Try printing empty list...
Merged list head is null (empty list)

Resources