Search code examples
clinked-listqueuepriority-queue

Sorting structures in a linked list based on the values of two fields


I want to sort values inside my priority queue that have the same priority. Everything is loaded from a simple .txt file. I already sorted all priorities, but now I would like to sort values that share the same priority.

My code is relatively simple. It has push and pop functions that, you've guessed it, push and pop haha.

Function ispis is made for printing. Also I know that declaring a dummy node is not a good idea, but they taught us that way at the uni so I got comfortable with it.

Here's an example how I would like to sort my elements:

E.g.

10 1 
2 1
3 1

to

2 1 
3 1
10 1 

My code:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct cvor* Red;
struct cvor {
    int el, pr;
    Red next;
};
void push(Red R, int b, int p);
void print(Red R);
void pop(Red R);

int main() {
    FILE* dat;
    int br, pr;
    struct cvor Head;
    Head.next = NULL;
    dat = fopen("redsp.txt", "r");

    if (!dat) {
        printf("No file!\n");
    }
        
    while (fscanf(dat, "%d %d", &br, &pr) != EOF) {
        push(&Head, br, pr);
    }
        
    printf("Printing:\n");
    print(Head.next);

    /*printf("\n\n\n");
    printf("poppin:D\n");
    for (int i = 0; i < 14;i++) {
        pop(&Head);
        printf("\n\n\n");
        print(Head.next);
    }*/

    fclose(dat);    
}

void push(Red R, int b, int p) {
    Red q;
    q = (Red)malloc(sizeof(struct cvor));

    q->el = b;
    q->pr = p;

    /*if (q->pr >p) {
        q->next = R;
        R = q;
    }*/

        while (R->next != NULL && R->next->pr < p)
        {   
            R = R->next;
        }
            
        q->next = R->next;
        R->next = q;    
    
}

void pop(Red R) {
    Red temp, pre;
    temp = R->next;
    pre = NULL;

    while (temp && temp->next) {
        pre = temp;
        temp = temp->next;
    }
    if (pre) {
        free(pre->next);
        pre->next = NULL;
    }

}


void print(Red R) {
    while (R != NULL)
    {
        printf("%d %d\n", R->el, R->pr);
        R = R->next;
    }
}

Solution

  • As I understand your problem, the question is how to compare data based on two values.

    The line

        while (R->next != NULL && R->next->pr < p)
    

    checks for the end of the list and compares one field of the node structure.

    To make the code more clear I suggest to replace the comparison with a function call.

    void push(Red R, int b, int p) {
        Red q;
        q = (Red)malloc(sizeof(struct cvor));
    
        q->el = b;
        q->pr = p;
    
        while (R->next != NULL && compare_nodes(R->next, q) < 0)
        {   
            R = R->next;
        }
                
        q->next = R->next;
        R->next = q;    
    }
    

    Your current comparison can be implemented as

    /**
     * Compare two nodes.
     *
     * This implementation compares only the pr fields.
     *
     * @param a Pointer to node A.
     * @param b Pointer to node B.
     *
     * @retval <0 if A < B
     * @retval 0  if A == B
     * @retval >0 if A > B
     */
    int compare_nodes(const struct cvor *a, const struct cvor *b) {
        /* here only the "pr" element is compared */
        int retval = a->pr - b->pr;
        return retval;
    }
    

    You can extend the function to compare other structure fields if the comparison result for the first field is "equal".

    int compare_nodes(const struct cvor *a, const struct cvor *b) {
        /* compare pr field first */
        int retval = a->pr - b->pr;
        /* compare el field if necessary */
        if (retval == 0) retval = a->el - b->el;
        return retval;
    }
    

    Note that in production code the functions should make sure that the arguments are not NULL pointers instead of relying on the caller.