Search code examples
cpriority-queue

Adding same priority items to a priority queue in C problem


I wrote a priority queue in C that accepts passenger info of a flight by using their priorities. There are three main ticket classes (Business, Economy, Standard) and Business has a special class as 'diplomat' and Economy has too as 'veteran'. Here is a list of input info with their corresponding priorities in parentheses:

Input: bus_1(1), eco_1(3), bus_2(1), eco_2(3), std_1(4), eco_3(3), eco_4(3), bus_3(0), bus_4(1), eco_6(2), eco_7(2)

Output: bus_3, bus_1, bus_4, bus_2, eco_7, eco_6, eco_4, eco_3, eco_2, eco_1, std_1

What it should be: bus_3, bus_1, bus_2, bus_4, eco_6, eco_7, eco_1, eco_2, eco_3, eco_4, std_1

0 is the highest priority and 4 is the least. I know my code is not correct but I can't figure out the correct way to write an algorithm to push the same priority item after the one already in the queue. Here is my function:

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

enum classes
{
    business,
    economy,
    standard
};

struct flight
{
    char flightName[8];

    //for priority queue
    struct queueNode *rootNode;
    int hasRoot;
    int businessQueueCount, economyQueueCount, standardQueueCount;
    int totalPassengerCount;

};

struct passenger
{
    char passengerName[15];
    char flightName[8];
};

struct queueNode
{
    struct passenger passenger;
    int priority;
    struct queueNode *next;
};

struct queueNode *newQueueNode(char flightName[8], char passengerName[15], int priority)
{
    struct queueNode *temp = malloc(sizeof(struct queueNode));
    temp->priority = priority;
    temp->next = NULL;
    strcpy(temp->passenger.flightName, flightName);
    strcpy(temp->passenger.passengerName, passengerName);

    return temp;
}


void pushQueue(struct queueNode **head, char *flightName, char *passengerName, int priority)
{
    struct queueNode *start = (*head);

    struct queueNode *temp = newQueueNode(flightName, passengerName, priority);

    if ((*head)->priority > priority)
    {
        temp->next = *head;
        (*head) = temp;
    }
    else
    {
        if (start->next != NULL && start->next->priority == priority)
        {
            temp->next = start->next->next;
            start->next->next = temp;
        }
        else
        {
            while (start->next != NULL && start->next->priority < priority)
            {
                start = start->next;
            }

            temp->next = start->next;
            start->next = temp;
        }
    }
}

struct passenger peekQueue(struct queueNode **head)
{
    return (*head)->passenger;
}

void popQueue(struct queueNode **head)
{
    struct queueNode *temp = *head;
    (*head) = (*head)->next;
    free(temp);
}

int main(){

    struct flight flight_temp;
    strcpy(flight_temp.flightName, "flight1");

    flight_temp.rootNode = newQueueNode(flight_temp.flightName, "bus_1", 1);
    pushQueue(&(flight_temp.rootNode), flight_temp.flightName, "eco_1", 3);
    pushQueue(&(flight_temp.rootNode), flight_temp.flightName, "bus_2", 1);
    pushQueue(&(flight_temp.rootNode), flight_temp.flightName, "std_1", 4);
    pushQueue(&(flight_temp.rootNode), flight_temp.flightName, "eco_3", 3);
    pushQueue(&(flight_temp.rootNode), flight_temp.flightName, "bus_3", 0);
    pushQueue(&(flight_temp.rootNode), flight_temp.flightName, "bus_4", 1);
    pushQueue(&(flight_temp.rootNode), flight_temp.flightName, "eco_4", 3);

    for (size_t i = 0; i < 6; i++)
    {
        printf("%s\n", peekQueue(&(flight_temp.rootNode)).passengerName);
        popQueue(&(flight_temp.rootNode));
    }






}

Thanks in advance for your help.


Solution

  • Essentially, your pushQueue function is trying to insert into a sorted list, making sure that if an equal item is already there, the new item goes after it. But you have a couple of problems in your code that make it fail. I've added some comments to your code to show you where the errors are.

    void pushQueue(struct queueNode **head, char *flightName, char *passengerName, int priority)
    {
        struct queueNode *start = (*head);
    
        struct queueNode *temp = newQueueNode(flightName, passengerName, priority);
    
        if ((*head)->priority > priority)
        {
            temp->next = *head;
            (*head) = temp;
            // if you put a return statement here, then you can get rid of
            // the else. It reduces nesting and makes your code cleaner.
        }
        else
        {
            // If the new item has the same priority as what's already in the list,
            // then you insert the new item right after it. What if there were two
            // or more items with the same priority? The new one wouldn't go
            // to the end of the list.
            // This code really is just a broken special case for the else below.
            if (start->next != NULL && start->next->priority == priority)
            {
                temp->next = start->next->next;
                start->next->next = temp;
            }
            else
            {
                // You want to insert the new item after any existing items that
                // have the same priority. But your logic will stop when it finds
                // the first node that has the same priority. So the new item
                // gets inserted at the front. You need to change '<' to '<='
                while (start->next != NULL && start->next->priority < priority)
                {
                    start = start->next;
                }
    
                temp->next = start->next;
                start->next = temp;
            }
        }
    }
    

    You can simplify your code quite a bit by combining your cases. And also get away from brain-bending expressions like start->next->next that are hard to reason about and easy to get wrong, resulting in trying to dereference a NULL pointer.

    void pushQueue(struct queueNode **head, char *flightName, char *passengerName, int priority)
    {
        struct queueNode *currentNode = (*head);
        struct queueNode *nextNode;
    
        struct queueNode *newNode = newQueueNode(flightName, passengerName, priority);
    
        // if the new node's priority is less than the head node's priority,
        // then the new node becomes the head.    
        if ((*head)->priority > priority)
        {
            newNode->next = *head;
            (*head) = newNode;
            return;
        }
    
        // Traverse the list looking for the first node whose priority
        // is greater than the new node's priority.
        nextNode = currentNode->next;
        while (nextNode != NULL && nextNode->priority <= priority)
        {
            currentNode = nextNode;
            nextNode = currentNode->next;
        }
        // at this point, you want to insert your new node between
        // currentNode and nextNode
        currentNode->next = newNode;
        newNode->next = nextNode;
    }
    

    You'll want to test that, of course. I didn't really change your algorithm: just combined your two special cases into one.