简体   繁体   中英

Writing a priority queue with a max heap structure in c++

I am writing a priority queue with a max heap structure as an assignment for school. I can either write it as an array or I can use a vector. I chose a vector. So the assignment is this, the user chooses options from a menu where he either wants to add,print, or view the elements. When the user chooses to add he gets ask who wants to be added, the instructor, student, or TA. He can enter i,I,t,T,S,s. The instructor having the highest priority where if the user chooses the option to print and there is an instructor in the queue he gets to go first. The TA having the second highest priority where if there is a TA and a student in the queue, the TA goes first. If there is is more than one instructor than the queue acts as a normal queue. I have written most of it, or tried. I got my max heap implementation from my textbook since they provide one. Now the problem is this, when I have more than one item in the priority queue and I choose to print, it crashes and gives me a vector subscript out of range exception. I been trying to fix it and no luck. Also, when I try to print the elements in the queue or print them, it needs to say the job# with the name of the person. Can someone help me find a way to implement that.

#pragma once
#include <vector>

struct Heap
{
    std::vector<int> m_elements;

    void ReHeapDown(int, int);
    void ReHeapUp(int, int);
    void Swap(int& a, int& b);
};

    #include "heap.h"

void Heap::ReHeapDown(int index, int bottom)
{
    int maxChild, rightChild, leftChild;

    leftChild = index * 2 + 1;
    rightChild = index * 2 + 2;

    if (leftChild <= bottom)
    {
        if (leftChild == bottom)
            maxChild = leftChild;
        else
        {
            if (m_elements[leftChild] <= m_elements[rightChild])
                maxChild = rightChild;
            else
                maxChild = leftChild;
        }
        if (m_elements[index] < m_elements[maxChild])
        {
            Swap(m_elements[index], m_elements[maxChild]);
            ReHeapDown(maxChild, bottom);
        }
    }
}

void Heap::ReHeapUp(int index, int bottom)
{
    int  parent;

    if (bottom  > index)
    {
        parent = (bottom - 1) / 2;
        if (m_elements[parent]  <  m_elements[bottom])
        {
            Swap(m_elements[parent], m_elements[bottom]);
            ReHeapUp(index, parent);
        }
    }
}

void Heap::Swap(int& a, int& b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

    #include <iostream>
#include "heap.h"
#pragma once

class PQTYPE
{

private:
    Heap m_Items;

public:
    bool isEmpty() const;
    void Enqueue(int, std::string);
    void Dequeue(int, std::string);
    void printElements();
};



#include "pqtype.h"

bool PQTYPE::isEmpty() const
{
    return m_Items.m_elements.empty();
}

void PQTYPE::Enqueue(int newItem, std::string lName)
{

    if (lName == "Student")
    {
        m_Items.m_elements.push_back(newItem);
        m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
    }
    else if (lName == "TA")
    {
        m_Items.m_elements.push_back(newItem);
        m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
    }
    else if (lName == "Instructor")
    {
        m_Items.m_elements.push_back(newItem);
        m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
    }
}

void PQTYPE::Dequeue(int item, std::string lName)
{
    if (isEmpty())
        std::cout << "No jobs to print\n";
    else
    {
        m_Items.m_elements[0] = m_Items.m_elements.back();
        std::cout << "Now printing Job#" << m_Items.m_elements[item - 1] << " " << lName.c_str() << std::endl;
        m_Items.m_elements.pop_back();
        m_Items.ReHeapDown(0, item - 1);
    }
}

void PQTYPE::printElements()
{
    if (isEmpty())
        std::cout << "No jobs to print\n";
    else
    {
        for (int i = 0; i < m_Items.m_elements.size(); i++)
        {
            std::cout << "Job#" << m_Items.m_elements[i] << std::endl;
        }
    }
}


#include"pqtype.h"

struct Person
{
    int m_priority;
    std::string m_name;

    Person()
    {
        m_priority = 0;
        m_name = " ";
    }
};

int showMenu();
void addJobs(PQTYPE&, Person&);
void printJobs(PQTYPE&, Person&);
void viewJobs(PQTYPE&);

int main()
{

    int option;
    Person p;
    PQTYPE pq;

    do
    {
        option = showMenu();

        switch (option)
        {
        case 1: addJobs(pq, p);
        break;
        case 2: printJobs(pq, p);
        break;
        case 3: viewJobs(pq);
        break;
        case 4:
        break;
        default: std::cout << "Wrong input\n";
        break;
        }

    } while (option != 4);


    return 0;
}

int showMenu()
{
    int choice;
    std::cout << " 1.)Add Job\n";
    std::cout << " 2.)Print Job\n";
    std::cout << " 3.)View Jobs\n";
    std::cout << " 4.)Exit\n";
    std::cout << " Enter Choice: ";
    std::cin >> choice;

    return choice;
}

void addJobs(PQTYPE& pq, Person& per)
{
    char jobChoice;

    std::cout << "Who is the job for ( Instructor(i or I), TA(t or T), Student(s or S) :";
    std::cin >> jobChoice;

    if (jobChoice == 'S' || jobChoice == 's')
    {
        per.m_priority++;
        per.m_name = "Student";
        pq.Enqueue(per.m_priority, per.m_name);
    }
    else if (jobChoice == 'T' || jobChoice == 't')
    {
        per.m_priority++;
        per.m_name = "TA";
        pq.Enqueue(per.m_priority, per.m_name);
    }
    if (jobChoice == 'I' || jobChoice == 'i')
    {
        per.m_priority++;
        per.m_name = "Instructor";
        pq.Enqueue(per.m_priority, per.m_name);
    }
}

void printJobs(PQTYPE& pq, Person& p)
{
    pq.Dequeue(p.m_priority, p.m_name);
}

void viewJobs(PQTYPE& pq)
{
    pq.printElements();
}

In your original code the index used inside Dequeue() for accessing the vector doesn't seem to be initialised in the right way. Let's assume that you have added two entries to your list. In this case the value of P.m_priority inside your main() is 2. Now you're calling printJobs() for the first time. printJobs() calls pq.Dequeue(p.m_priority, p.m_name), so Dequeue() gets p.m_priority as its parameter item . Keep in mind that item has the value 2.

m_Items.m_elements[0] = m_Items.m_elements.back();
std::cout << "Now printing Job#" << m_Items.m_elements[item - 1] << " " << lName.c_str() << std::endl;
m_Items.m_elements.pop_back();

You're accessing your std::vector using an index of item - 1 . This works for the first time, as there are two elements in your list. In this call, there is also a pop_back() done on your list, which decreases its size by one. The next time you call printJobs(), the given parameter item won't have changed, it still has the value 2. When you access your Itemlist, there is no longer an index of 1, and an subscript out of range exception will be thrown.

There were no fixed priorities assigned to the three entry types in your original version, so I added these (see addJobs() ).

So a possible solution to store the person's name could look like this:

struct Person
{
    int m_priority;
    std::string m_name;

    Person()
    {
        m_priority = 0;
        m_name = " ";
    }
};

struct Heap
{
    std::vector<Person> m_elements;

    void ReHeapDown(int, int);
    void ReHeapUp(int, int);
    void Swap(Person& a, Person& b);
};

void Heap::ReHeapDown(int index, int bottom)
{
    int maxChild, rightChild, leftChild;

    leftChild = index * 2 + 1;
    rightChild = index * 2 + 2;

    if (leftChild <= bottom)
    {
        if (leftChild == bottom)
            maxChild = leftChild;
        else
        {
            if (m_elements[leftChild].m_priority <= m_elements[rightChild].m_priority)
                maxChild = rightChild;
            else
                maxChild = leftChild;
        }
        if (m_elements[index].m_priority < m_elements[maxChild].m_priority)
        {
            Swap(m_elements[index], m_elements[maxChild]);
            ReHeapDown(maxChild, bottom);
        }
    }
}

void Heap::ReHeapUp(int index, int bottom)
{
    int  parent;

    if (bottom  > index)
    {
        parent = (bottom - 1) / 2;
        if (m_elements[parent].m_priority  <  m_elements[bottom].m_priority)
        {
            Swap(m_elements[parent], m_elements[bottom]);
            ReHeapUp(index, parent);
        }
    }
}

void Heap::Swap(Person& a, Person& b)
{
    Person temp;
    temp = a;
    a = b;
    b = temp;
}

#include <iostream>

class PQTYPE
{

private:
    Heap m_Items;

public:
    bool isEmpty() const;
    void Enqueue(Person);
    void Dequeue();
    void printElements();
};

bool PQTYPE::isEmpty() const
{
    return m_Items.m_elements.empty();
}

void PQTYPE::Enqueue(Person newItem)
{

    if (!newItem.m_name.compare("Student"))
    {
        m_Items.m_elements.push_back(newItem);
        m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
    }
    else if (!newItem.m_name.compare("TA"))
    {
        m_Items.m_elements.push_back(newItem);
        m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
    }
    else if (!newItem.m_name.compare("Instructor"))
    {
        m_Items.m_elements.push_back(newItem);
        m_Items.ReHeapUp(0, m_Items.m_elements.size() - 1);
    }
}

void PQTYPE::Dequeue()
{
    if (isEmpty())
        std::cout << "No jobs to print\n";
    else
    {
        Person front = m_Items.m_elements.front();
        std::cout << "Now printing Job#" << front.m_priority << " " << front.m_name.c_str() << std::endl;
        m_Items.m_elements.erase(m_Items.m_elements.begin());
        m_Items.ReHeapDown(0, m_Items.m_elements.size() - 1);
    }
}


void PQTYPE::printElements()
{
    if (isEmpty())
        std::cout << "No jobs to print\n";
    else
    {
        for (int i = 0; i < m_Items.m_elements.size(); i++)
        {
            std::cout << "Job#" << m_Items.m_elements[i].m_priority << " " << m_Items.m_elements[i].m_name.c_str() << std::endl;
        }
    }
}

int showMenu();
void addJobs(PQTYPE&, Person&);
void printJobs(PQTYPE&, Person&);
void viewJobs(PQTYPE&);

int showMenu()
{
    int choice;
    std::cout << " 1.)Add Job\n";
    std::cout << " 2.)Print Job\n";
    std::cout << " 3.)View Jobs\n";
    std::cout << " 4.)Exit\n";
    std::cout << " Enter Choice: ";
    std::cin >> choice;

    return choice;
}

void addJobs(PQTYPE& pq, Person& per)
{
    char jobChoice;

    std::cout << "Who is the job for ( Instructor(i or I), TA(t or T), Student(s or S) :";
    std::cin >> jobChoice;

    if (jobChoice == 'S' || jobChoice == 's')
    {
        per.m_priority = 0;
        per.m_name = "Student";
        pq.Enqueue(per);
    }
    else if (jobChoice == 'T' || jobChoice == 't')
    {
        per.m_priority = 1;
        per.m_name = "TA";
        pq.Enqueue(per);
    }
    if (jobChoice == 'I' || jobChoice == 'i')
    {
        per.m_priority = 2;
        per.m_name = "Instructor";
        pq.Enqueue(per);
    }
}

void printJobs(PQTYPE& pq)
{
    pq.Dequeue();
}

void viewJobs(PQTYPE& pq)
{
    pq.printElements();
}

int main()
int option;
    Person p;
    PQTYPE pq;

    do
    {
        option = showMenu();

        switch (option)
        {
        case 1: addJobs(pq, p);
        break;
        case 2: printJobs(pq);
        break;
        case 3: viewJobs(pq);
        break;
        case 4:
        break;
        default: std::cout << "Wrong input\n";
        break;
        }

    } while (option != 4);

    return 0
}

Are you sure that the methods ReHeapUp and ReHeapDown meet your requirements? And shouldn't there be a distinction between job number and priority?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM