c++ Linked List with priority queue - c++

I trying to code out the Linked List with priority queue and i encountered some problem.
I have about 7 priority from 1 the most to 7 the least important.
here's my current insert method.
void queue::addToQueueList(int newPriority, double newFare, int custID)
{
node* newnode= new node;
newnode->priority= newPriority;
newnode->fare = newFare;
newnode->cusID = custID;
newnode->next= NULL;
if (isempty())
{
front = back = newnode;
}
else
{
node* temp = front;
if(newnode->priority < temp->priority)
{
newnode->next = front;
front = newnode;
}
else
{
while(newnode->priority < temp->priority)
{
if(temp->next == NULL)
{
break;
temp = temp->next;
}
}
if(temp->next == NULL && newnode->priority < temp->priority)
{
back->next = newnode;
back = newnode;
}
else
{
newnode->next = temp->next;
temp->next = newnode;
}
}
}
}
Invoked as:
qList->addToQueueList(2, 488.88, A);
qList->addToQueueList(1, 388.88, B);
qList->addToQueueList(3, 488.88, C);
Expected result should be :
B, A, C
THe result shows :
B, C, A

Your making this considerably harder than it needs to be. Ultimately you need to walk the list, find the insertion point, remember how you arrived at that insertion point, and wire both your fore and aft pointers appropriately. Also a priority queue has no reason to keep a "back" pointer, so I'm not sure why you have one.
There are a number of ways to do this. First, to make the code cleaner to understand, providing a proper parameterized constructor for node is both trivial and helpful:
struct node
{
int priority;
double fare;
int cusID;
node *next;
node(int p, double f, int id, node *nxt = nullptr)
: priority(p), fare(f), cusID(id), next(nxt)
{
}
};
One you have that, you can go down the road you were apparently trying to navigate, using a pointer-value list walking approach. To do that you need to maintain a previous pointer:
void queue::addToQueueList(int newPriority, double newFare, int custID)
{
node* temp = front, *prev = NULL;
while (temp && temp->priority < newPriority)
{
prev = temp; // remember how we got here
temp = temp->next; // advance to next node
}
// create new node, linking to temp
node *newnode = new node(newPriority, newFair, custID, temp);
// link to previous node or assign as new head, whichever is needed
if (prev != nullptr)
prev->next = newnode;
else
head = newnode;
// though there is no need for a back pointer in a priority queue
// you had one none-the-less, so....
if (!temp)
back = newnode;
}
it is worth noting that this algorithm will insert new arrivals with similar priority at the head of that priority section of the list. I.e. the newest arrivals for a given priority are always at the forefront of that priority's position in the queue. If you want the oldest arrivals of a given priority to be "ahead" of their brethren, you simply need to change this:
while (temp && temp->priority < newPriority)
to this:
while (temp && temp->priority <= newPriority) // note < is now <=
Best of luck.

The comparison in your while loop is wrong. When inserting C newnode->priority == 3 and temp(B)->priority == 1. Thus the while loop is never entered.
Also, the temp = temp->next inside the while loop should be outside (after) the if statement. Otherwise this will be an infinite loop.
Assuming you are correcting these: you will always insert the new element after temp. Be aware of this in your fix of your comparisons. You are likely to add comparisons with temp->next->priority as well.
I agree with Joachim in the comments: step through the code with a debugger. Then you can see the values of the variables and which comparisons produce which results.

Related

Pointer in deleting a node in single linked list

In place of *head_ref = temp->next;, why can't I assign it as *head_ref = *head_ref->next?
Why should I use temp? Aren't they pointing to the same place?
class Node{
public:
int data;
Node* next;
};
void deleteNode(Node** head_ref, int key){
Node* temp = *head_ref;
Node* prev = NULL;
if(temp!=NULL && temp->data==key){
*head_ref = temp->next;
delete temp;
return;
}
else{
while(temp!=NULL && *head_ref->data!=key){
prev = temp;
temp = temp->next;
}
}
Your code does not compile, *head_ref->data should be (*head_ref)->data.
The reason why you should use temp is that you want to modify *head_ref only if the element you want to delete is the head element. If you delete any other element of the list, the head pointer must stay the same.
But your code is wrong anyway. You're doing things in the wrong order. You must first find the element you want to delete, and then handle the deletion.
Your code handles the deletion first and then finds the element to delete which is absurd.
You want this:
void deleteNode(Node** head_ref, int key) {
Node* current = *head_ref;
Node* previous = NULL;
// find element to delete
while (current && current->data != key)
{
previous = current;
current = current->next;
}
// if current is NULL here then the element has not been found
if (current != NULL)
{
// element found,
// current points to element found
// previous points to previous element or NULL if current is head
if (previous == NULL)
{
// deleting head element -> we need to update head_ref
*head_ref = current->next;
}
else
{
// deleting any other element -> update next pointer of previous element
previous->next = current->next;
}
delete current;
}
}
That being said, this is rather C code than C++ code. You should use standard containers rather than making your own, or at least use C++ idioms such as constructors.

Problem with inserting into a doubly linked list in ascending order

i need to make a function to sum 2 piecewise linear functions (both decreasing or increasing) and insert them into a third list in an ascending order based on the x-axis coordinates of each point. So i have created multiple functions, all seem to check out except this one yet i do not know what's the problem. It's not inputting anything at all.
struct coords has double x,y;
dList has : coords pt;
node has : node *head, *tail;
node *prev, *next;
dList insert(dList L, coords point) {
node *temp;
temp = new node;
if (temp == NULL) {
cout << "error";
exit(1);
}
temp->next = NULL;
temp->prev = NULL;
temp->pt = point;
if (L.head == NULL || L.tail == NULL) {
L.head = temp;
L.tail = temp;
return L;
}
if (L.head->pt.x > temp->pt.x) {
temp->next = L.head;
L.head->prev = temp;
L.head = temp;
return L;
}
if (L.tail->pt.x < temp->pt.x) {
temp->prev = L.tail;
L.tail->next = temp;
L.tail = temp;
return L;
}
node *cur;
cur = L.head->next;
while (cur->pt.x < temp->pt.x)
cur = cur->next;
temp->next = cur->next;
temp->prev = cur;
cur->next->prev = temp;
cur->next = temp;
return L;
}
The case in which the node to be inserted is in the middle is the problem. You should be looking one node ahead instead of looking at the current one. Try working it out on paper and you will see how that makes a difference:
node * cur;
// also start at head here
cur=L.head;
while(cur->next->pt.x<temp->pt.x)
cur=cur->next;
temp->next=cur->next;
temp->prev=cur;
cur->next->prev=temp;
cur->next=temp;
You should also consider passing a dList L as a pointer to the function and also returning it as a pointer:
// this way you won't be making a copy of it, you may run into trouble if you don't have your copy constructor implemented
dList* insert(dList* L,coords point)
I hope that this helps you.

Linked list issue with multiple parameters

So I am trying to sort nodes according to their location (an integer) and then by the date (year and month). When I use my overloaded operator to print my linked list, it shows that the list is only inserting one of the wanted nodes meaning that my insert function is not correct. It is not giving any errors, it is just not running as expected. My insert function is below. Does anyone have any ideas as to what is wrong?
void LinkedList::insert(int location, int year, int month, double temperature) {
// Implement this function
Node* newNode = new Node();
newNode->loc = location;
newNode->yr = year;
newNode->mo = month;
newNode->temp = temperature;
Node* tempNode = head;
Node* previousNode = nullptr;
if(tail == nullptr & head == nullptr){
head = newNode;
}
while(tempNode != nullptr){
if((tempNode->loc == newNode->loc) && (tempNode->yr == newNode->yr)){
if(tempNode->mo > newNode->mo){
newNode->next = tempNode->next;
tempNode->next = newNode;
}
if(tempNode->mo < newNode->mo){
newNode->next = tempNode;
}
}
if(tempNode->loc > newNode->loc){
newNode->next = tempNode->next;
tempNode->next = newNode;
}
if(tempNode->loc < newNode->loc){
newNode->next = tempNode->next;
tempNode->next = newNode;
}
tempNode = tempNode->next;
}
}
The reason you are not getting the linkedlist properly is because you are making a mistake in pointer manipulation. When you assign cur->next=data->next;
you are basically breaking the list since data->next doesnot point to next node in the list.
Also, note that since this is a single linked list [meaning it has only one pointer forward] you can only insert nodes ahead of the current node.
Try something like this:
if (cur->loc > data->loc) {
data->next = cur->next; // This will insert data in middle of
cur->next = data; // cur and cur->next
}
There are multiple checks you will need to do if you want to insert in a increasing or decreasing order.
Make different cases for when you insert the first element of the list, insert at head, insert at tail and insert in the middle of linkedlist.
Also, at tail node make sure that its next is always set to null.

Traversing linked list and modifying or inserting node C++

I am attempting to write a function that will traverse a linked list, wherein the nodes represent terms of a polynomial. Each node includes fields for coefficient (a double named coeff), power (a size_t named power), and link (a NodePtr *next). The function is called with a double variable value, which represents the coefficient the node should have, and a size_t variable i, which represents its power. The function should traverse the linked list looking for the node with power i. If the list already contains a node with power i, its coefficient should be changed to hold the new value. If it did not previously have a node with power i, such a term should be added with the coefficient value. The list should be ordered by power (i.e. the node with power 3 should be the node 3 in the list).
Below is the code I have written thus far, though it currently generates the following error:
Unhandled exception at 0x0130D2FA in Project 3.exe: 0xC0000005: Access violation writing location 0x0000000C.
I cannot figure out why the error is generated, so that is my first issue. The second is that I believe my function may have some logical errors and does not correctly modify and create new nodes.
I have been stumped on this for days and cannot test my other functions without this having this one in working order, so any help would be greatly appreciated! Thank you!
void Poly::setCoeff(double value, size_t i)
{
if (0 <= i){
Node* prev = new Node();
Node* curr = new Node();
Node* newNode = new Node();
newNode->coeff = value;
newNode->power = i;
curr = myHead; // Initialize curr to myHead;
if (curr != nullptr)
{
while (curr->next != nullptr && curr->power != i)
{
prev = curr;
curr = curr->next;
}
if (curr->power == i)
{
curr->coeff = value;
}
else if (curr->next == nullptr && i == curr->power + 1)
{
curr->next = new Node; // Creates a node at the end of the list
curr = curr->next; // Points to that node
curr->next = nullptr; // Prevents it from going any further
curr->power = i;
curr->coeff = value;
}
else
{
prev->next = newNode;
newNode->next = curr;
}
}
else
{
curr->next = newNode;
curr = curr->next;
}
}
else
{
throw std::out_of_range("Index out of range");
}
}
It is a series of clear incorrect assumptions of how dynamic memory is managed in C++ that is getting you into heap-loads of trouble in this code. Were this not an academic exercise I would tell you simply to throw it all away and use:
std::map<size_t, double>
also known as: The Good Stuff. It would do literally everything you need this code to accomplish.
But this is academia. Like most things in academia they make you crawl through trenches before you learn how it should be. So, I will expose what is deficient in your code, but suffice it to say, once you learn all this you will strive not to have to do it in the first place by using tools already available to you.
In other words, unless someone said I had to do this with a hand-coded linked list implementation, I would use the above map instead. You can't (yet), but know it is there.
Your Code
You didn't include the definition of Node, but I can only assume it looks something like this:
struct Node
{
double coeff;
size_t power;
Node *next;
};
Whether this is nested within class Poly or not (and it likely should be if the latter) is likewise unclear. It isn't entirely relevant to the question, but mentioned here to attempt to drive home that, when asking a question on SO, provide enough info to minimize assumptions that may affect the answers your getting.
With that your code:
void Poly::setCoeff(double value, size_t i)
{
if (0 <= i) // NOTE: not needed, unsigned, will always be i >= 0
{
Node* prev = new Node(); // NOTE: wrong. leaks memory.
Node* curr = new Node(); // NOTE: same as above
Node* newNode = new Node(); // NOTE: **may** leak (see below)
newNode->coeff = value;
newNode->power = i;
curr = myHead;
if (curr != nullptr) // OK: check for null good
{
// NOTE: should be checking `curr`, not curr->next
while (curr->next != nullptr && curr->power != i)
{
prev = curr;
curr = curr->next;
}
// NOTE: should check curr for NULL first.
if (curr->power == i)
{
curr->coeff = value;
}
// NOTE: same here. also,
else if (curr->next == nullptr && i == curr->power + 1)
{
// NOTE: this code path will leak newNode allocated at the
// top of the function.
curr->next = new Node;
curr = curr->next;
curr->next = nullptr;
curr->power = i;
curr->coeff = value;
}
else
{
prev->next = newNode;
newNode->next = curr;
}
}
else
{ // NOTE: this is where your mainline fault is coming from. you
// just validated curr can be NULL here (and will be on initial)
curr->next = newNode;
curr = curr->next;
}
}
// NOTE: this can't happen, as i can never be less than zero
else
{
throw std::out_of_range("Index out of range");
}
}
The following are somewhat obvious.
Your memory management is not correct, and includes introducing memory leaks.
Your pointer management is likewise poor. Pointers are not like Java references, and nothing will get you in trouble faster in a C/C++ program than improper pointer management.
The algorithm doesn't maintain the mandate the list be ordered.
Changes to Your Code
The requirements for your code mandate an ordered list is maintained, yet your coefficient insertion algorithm makes no attempts at fulfilling that requirement. The setCoeff member is required to insert a new term if the matching exponent cannot be found, and if kept sorted, you'll know by proper enumeration whether that is the case by discovering (a) an exponent beyond yours, or (b) the end of the list, whichever happens first.
i is a size_t value, which means it is a magnitude for object counting. The standard mandates size_t is unsigned, which means it cannot be negative. This means checking for i >= 0 is useless. It will always be so.
A new node is allocated before know you need one. Remember, this is supposed to update an existing node if you find a matching exponent entry. Only if there were no match should a new node be required.
Your first-insert detection needs a complete redeux. It is guaranteed to invoke undefined behavior.
First make it easier on yourself. Provide a Node constructor that sets up a node via parameters so you can stop littering your code with that setup. In doing so, it becomes both easier to read and safer, since you initialize all member variables at construction.
struct Node
{
Node *next;
double coeff;
size_t power;
Node(double coeff_, size_t power_, Node *next_=nullptr)
: coeff(coeff_), power(power_), next(next_)
{}
};
With that, things will get considerably easier. The punch list above can be fulfilled with the following changes:
void Poly::setCoeff(double value, size_t i)
{
Node *prev = nullptr; // points to prior node
Node *curr = myHead; // points to current node
while (curr && curr->power < i)
{
prev = curr; // remember current node...
curr = curr->next; // ... then move to next node
}
// only allocate a new node if
// (a) we reached the end of the list (curr == NULL)
// (b) we reached a node with non match (will be larger exponent)
if (!curr || curr->power != i)
{
// **NOW** allocate the new node. we know we need one and we
// have a pretty solid idea where it goes.
Node *newNode = new Node(value, i, curr);
// if prev is set, then it means the new node goes somewhere
// *past* the head pointer otherwise it will become the new head.
if (prev)
prev->next = newNode;
else
myHead = newNode;
}
else
{ // found matching node
curr->coeff = value;
}
}
I sincerely hope it helps, and wish you the best of luck in trenching through the cruft before you get to The Good Stuff. Its worth it in the end.
I will follow up with the answer using a std::map (as WhozCraig's excellent answer mentions):
#include <map>
#include <iostream>
typedef std::map<size_t, double> Polynomial;
void AddCoefficientAndPower(Polynomial& poly, double coeff, size_t power)
{
// This does everything your assignment asked for, except for implementing
// all of that linked list stuff
poly[power] = coeff;
}
using namespace std;
int main()
{
Polynomial myPoly;
// add the coefficient and power
AddCoefficientAndPower(myPoly, 3, 1);
AddCoefficientAndPower(myPoly, 4, 2);
AddCoefficientAndPower(myPoly, 9, 0);
AddCoefficientAndPower(myPoly, 6, 3);
// This one will replace the previous (4,2)
AddCoefficientAndPower(myPoly, 3, 2);
// write out the coefficients followed by the power
Polynomial::iterator it = myPoly.begin();
while (it != myPoly.end())
{
cout << it->second << "^" << it->first << "\n";
++it;
}
}
Output:
9^0
3^1
3^2
6^3
Basically your entire assignment is a one line C++ statement in AddCoefficent that inserts an item in the map, and replaces an existing entry if one did exist.
Note -- no memory leaks, no calls to new, no crashes, etc.
Also, if your requirements were to also include any integral power value, then the above method works for negative, 0, and positive power values.

C++ Add to linked list in sorted order

Hi I have a linked list using structs. Right now I got it to add every element at the end. However I'd like to add each element in sorted order based on the ID. The struct has two elements: string name, and long ID.
node* temp = new node;
temp->name = nameRead;
temp->id = idRead;
//check if first item, if so add as head
if(head == NULL)
{
head = temp;
}
else
{
node* temp2 = head;
while(temp2->next != NULL)
{
temp2 = temp2->next;
}
temp2->next = temp;
}
node* temp = new node;
temp->name = nameRead;
temp->id = idRead;
node* temp2 = head;
node** temp3 = &head;
while(temp2 != null && temp2->id < temp->id)
{
temp3 = &temp2->next;
temp2 = temp2->next;
}
*temp3 = temp;
temp->next = temp2;
EDIT: Explanation: The 'temp3' pointer points to where 'temp' would need to go. Initialize temp2 to head, and keep looping until we reach the end of the list, or until temp2's id is >= than temp's id. In each iteration of the loop, advance both temp3 and temp2.
At the end of the loop, 'temp3' will hold the address of the pointer where temp should be. So assign *temp3 to point to temp, and assign temp->next to point to temp2 (which at this point would either be null, or would point to the item that has larger id than temp->id).
Taken from my student notebook:
void addSorted(node * head, int id){
node* newNode = new node;
newNode->number = n;
newNode->next = NULL;
if(head == NULL || head->number >= id ){
newNode->next = head;
head = newNode;
return;
}else if(head->next != NULL && head->next->id >= id){
node * nextNode = head->next;
newNode->next = nextNode;
head->next = newNode;
return;
}else{
node * left;
node * right = head;
while(right != NULL && right->next->id <= id){
left = right;
right = right->next;
}
left->next=newNode;
newNode->next = right;
}
}
Most of the modification to the code is pretty trivial -- just add a comparison based on the ID so you only walk through the list until you get to a node with an ID larger then the new one you need to insert (or reach the end of the list).
This is where things get slightly tricky: before you "realize" you've reached the right spot in the list, you've already gone one node too far (and in a singly linked list, there's no way to go back). The trick to fix that is pretty simple: allocate a new (empty) node and insert it after the too-large node you found. Copy that too-large node's contents into the new one you just inserted, and then copy the data for the new node into the spot it just vacated.
I should add, however, that all of this is mostly a moot point. If you want a sorted collection of items, a linked list is usually a really lousy choice. Unless you're doing something like homework where you have no choice but to do whatever brain-dead crap you've been assigned, look up std::set [Edit: or std::multiset, if duplicates are allowed -- or possibly std::map or std::multimap, if you want to be able to find a node based on an ID] and forget about implementing it yourself.