C++ linked list with classes - c++

So I have a problem with my head node changing when I add a new node to the list. I have to read in multiple lines from a file. Each line is going to be a function f(x) = ... and the nodes are singular expressions in the function so node 1 for example can be 25x^2 and node 2 could be 15x. So my Node class holds the coefficient so for node 1 it would be 25, and the exponent x goes to. Here's the pieces of code that are causing the problem I think.
Node* n = new Node();
List nodeList;
nodeList.setHead(NULL);
while(not at the end of line)
{
//This while loop just inputs from file, and stores values into Node class.
if(!nodeList.getHead()) //so this is first node being input.
{
//i collect the values for coefficient and exponent here...
n->setCoef(coef);
n->setExp(exp);
nodeList.insertNode(n);
}
else //so this is not the first node in the list.
{
//i collect the values for coefficient and exponent again here...
//After this code below, the head node changes to n's coef and exp.
//I know this is because n is still pointing at the head node
//but I keep getting runtime errors when trying to fix this.
n->setCoef(coef);
n->setExp(exp);
nodeList.insertNode(n);
}
}
Here is my List::insertNode(Node* n) class:
void List::insertNode(Node* n){
//if theres no head node, just set it to the n node and continue.
if (!head)
head = n;
else{
Node* ptr = head; //used to traverse through list.
bool likeTerms = false;
while(ptr) //This while loop checks to make sure theres no like terms.
{
if (ptr->getExp() == n->getExp()){
likeTerms = true;
break;
}
ptr = ptr->getNext();
}
//If they aren't like terms, just add the node to the end.
if (!likeTerms){
ptr = head;
while(ptr->getNext() != NULL)
{
ptr = ptr->getNext(); //traverses to the last node in list.
}
ptr->setNext(n); //Adds the new node to the spot after the last node
}
else if (likeTerms == true)//If the x exponents have like terms,
//then just combine them.
ptr->setCoef(ptr->getCoef()+n->getCoef());
}
}

The code to insert node for each line can also be simplified as following since the two statements of if-else condition are equivalent. The variable of Node* n need to be created in the while-loop or the nodeList would contain only one node with the last item of the function f(x).
while (not at the end of line)
{
Node* n = new Node;
n->setCoef(coef);
n->setExp(exp);
nodeList.insertNode(n);
}
The function void List::insertNode(Node* n) can also be simplified. The following is the simplified version.
void List::insertNode(Node* n) {
Node* ptr = header;
Node* prev = NULL;
bool same_exp_occurred = false;
while (ptr) {
if (n->getExp() == ptr->getExp()) {
ptr->setCoef(ptr->getCoef()+n->getCoef());
same_exp_occurred = true;
break;
}
prev = ptr;
ptr = ptr->getNext();
}
if (!same_exp_occurred && prev) {
prev->setNext(n);
}
}

Related

Why am I getting this runtime error: member access within null pointer of type 'Solution::node' (solution.cpp)

I was solving a question on leetcode 1409. Queries on a Permutation With Key, but I am getting this runtime error I don't know why. I am unable to debug this error.
Problem Statement:Given the array queries of positive integers between 1 and m, you have to process all queries[i] (from i=0 to i=queries.length-1) according to the following rules:
In the beginning, you have the permutation P=[1,2,3,...,m].
For the current i, find the position of queries[i] in the permutation P (indexing from 0) and then move this at the beginning of the permutation P. Notice that the position of queries[i] in P is the result for queries[i].
Return an array containing the result for the given queries.
My approach: I created a linkedlist to store the integers form 1 to m.
Then according to each query, I pass it to a function getpos() which returns the position of that query in the list and then updates it as per the directions given in problem statement.
This return value is then added to a result vector which is supposed to be the final answer after all queries are processed.
I have added comments to better understand my code
class Solution {
public:
struct node {
int data;
node* next = NULL;
};
node* addnode(node* head, int data) {
if(head == NULL) {
head = new node;
head->data = data;
}
else {
node* temp = head;
while(temp->next != NULL) { temp = temp->next; }
temp->data = data;
}
return head;
}
int getpos(node** head, int data) { //To get position of given query
int count = 0;
node* temp = *head;
node* prev;
while(temp->data != data) { //runtime error:member access within null pointer of type 'Solution::node' (solution.cpp); SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:32:21
prev = temp;
temp = temp->next;
count++;
}
prev->next = temp->next; //searched node deleted
temp->next = *head; //add the searched node to beginning of the list
*head = temp; //udapate head
return count; //we have position stored in count;
}
vector<int> processQueries(vector<int>& queries, int m) {
node* head = NULL;
for(int i=0;i<m;i++) { head = addnode(head,i+1); }
int n = queries.size();
vector<int> result;
for(int i=0;i<n;i++) { result.push_back(getpos(&head,queries[i])); }
return result;
}
};
Please debug and explain the cause of the error. I face many runtime errors which I fail to debug.
Your add_node function is bugged. Just take a deep breath and look at the code. add_node should allocate a node using new every time it is called. Ask yourself how many times and under what circumstances your version allocates a new node?
I'm sure you can see that your code only allocates a new node when head equals NULL, therefore it must be bugged.
Incidentally if you wanted a linked list why didn't you use std::list? You would have avoided the mistake you made.

Deletion of second largest element from a singly linked list

I'm currently trying to write a data structure framework for myself. Deletion of the second largest node from a singly linked list works flawlessly in ordinary cases. But fails in a particular one. Here's what I've already tried :
//node.h
typedef struct Node {
int value;
struct Node *nextNode;
} Node;
//linkedlist.h
typedef struct LinkedList{
Node *head;
int count;
} LinkedList;
//liblinkedlist.c
int deleteSecondLargest(LinkedList *list){
if(list->count==0)
return 1;
if(list->count==1)
return 2;
Node *temp = list->head;
Node *largest = temp;
Node *prev = NULL;
Node *prev1 = NULL;
Node *ptr = temp;
//finding the second largest node
while(temp!=NULL){
if(temp->value > largest->value){
largest = temp;
}
else if((temp->value!=largest->value) && (temp->value > ptr->value)){//here's the code failing
prev1 = prev;
ptr = temp;
}
prev = temp;
temp = temp->nextNode;
}
//deleting it
if(ptr==list->head)
list->head = list->head->nextNode;
else
prev1->nextNode = ptr->nextNode;
free(ptr);
list->count--;
return 0;
}
The code fails in the commented block whenever the items in the list are in the order of 1332->34->N.
I can understand why it is failing because both temp and ptr is holding 1332 and else if is returning false in the second iteration, but I can't find any solution to it. Also, the files in which the functions reside has been commented above the function definition.
Any help?
As far as I see, you have a problem with the first part of your code: finding the second-largest element in a single-linked list.
In fact, there're three problems in this code:
The ptr is initialized with first element, which may be too large to be the second maximum.
No node is ever demoted from largest to ptr. That means, for list 34 -> 1332 -> N your code also does not work.
If two maximums have equal values, second one is ignored. That means, for list 123 -> 123 -> N your code also does not work.
The algorithm of finding two maximums works as follows:
Initialization: initialize two current maximums with the lowest possible values or special "uninitialized" flag.
In loop over all the elements:
Update both maximums using the current value.
Implementation:
// Initialization
Node *largest = nullptr; // for maximum, nullptr means "not initialized"
Node *largest2 = nullptr; // for second maximum, nullptr means "not initialized"
Node *prev_largest = nullptr; // for previous node for maximum
Node *prev_largest2 = nullptr; // for previous node for second maximum
// Iterations
for (Node *cur = list->head, *prev = nullptr; // start of the loop: current node is head, prev is null
cur != nullptr; // end of the loop: current node is null
prev = cur, cur = cur->nextNode) { // loop iteration: move both current and prev nodes forward
if (largest == nullptr || cur->value > largest->value) { // check if we need to update maximum
// the node which was maximum is now second maximum
prev_largest2 = prev_largest;
largest2 = largest;
// current node is now maximum
prev_largest = prev;
largest = cur;
} else if (largest2 == nullptr || cur->value > largest2->value) { // check if we need to update second maximum
// current node is now second maximum
prev_largest2 = prev;
largest2 = cur;
}
}
// End of algorithm
// Second maximum is now in variable largest2
// Previous node for second maximum is now in variable prev_largest2
Also, please note this algorithm works even if your list contains less than 2 elements (in this case largest2 will be nullptr at the end).

c++ Linked List with priority queue

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.

Why isn't my remove node function working?

I've checked the boards and could not find any help with this. I find it easy to implement recursive functions given base and general cases, but this doesn't work the way I do it. I'm supposed to iterate down a list until I reach the tail of a linked list. If the next node is NULL, then I have to store the value at the last node, remove that node, and return the value. So it's similar to a dequeue method, except it's performed recursively. What am I doing wrong?
int LinkedList::removeTailRec(Node *n)
{
// check for the base case(s)
if(n->next == NULL)
{
Node *tmp = new Node();
tmp = n;
int val = n->value;
tmp = NULL;
return val;
}
else
return removeTailRec(n->next);
// else call the recursive method
}
First, I recommend you use nullptr instead of NULL.
Then, onto your code. You're actually not removing anything from your list.
if(n->next == NULL)
{
Node *tmp = new Node();
^^^^^^^^^^
//Useless, and dangerous. This memory is never free'd
tmp = n;
int val = n->value;
tmp = NULL;
^^^^^^^^^^
//You just set a local variable to NULL, you're not deleting anything
return val;
}
If you want to remove the node, you'll have to keep a reference to the previous node (e.g. having a doubly linked list, that is, having a pointer to the next element and a pointer to the previous element in each node, or working on the previous node directly).
Set this previous node's next to nullptr, store the node's value and then delete the Node pointer.
One way to do this is to work with the pointer to the next node :
int LinkedList::removeTailRec(Node *n)
{
//EDIT: Adding a check for n validity
if(!n){
//Here, you should have a way of detecting
//a call to your method with a null pointer
return 0;
}
Node* nextNode = n->next;
// check for the base case(s)
if(nextNode->next == nullptr)
{
//Get the next node value
int val = nextNode->value;
//Set the current node next member to nullptr
n->next = nullptr;
//Free the last node
delete nextNode;
return val;
}
else{
return removeTailRec(n->next);
}
// else call the recursive method
}
You are storing the result but not deleting it from linked list. You can return result in another variable (pointer : result).
Node* getTail(Node *n,int *result){
//u can even free the memory
if(!n->next)
{
result=n->value;
return NULL;
}
n->next=getTail(n->next,result);
}
or you can do it other way
int getTail(Node *n)
{
if(!n) return 0;
if(n->next)
{
if(!n->next->next)
{
Node *frnode=n->next;
int result=n->next->value;
n->next=NULL;
delete frnode;
return result;
}
getTail(n->next);
}
You are not removing last node in your code, and you leak another (temporary) node here.
To remove last node you have to zero the link in the previous node.
Your code should look like
...
if (n == NULL || n->next == NULL)
throw std::out_of_range("node");
if(n->next->next == NULL)
{
int val = n->next->value;
delete n->next;
n->next = NULL;
return val;
}
else ...
Be aware of the fact that c++ is not a functional language and has no optimizations for tail recursion, so in real application as your lists grow big enough you'll eventually have failure with stack overflow =) use Haskell or Erlang for this style of programming, in c++ use for or while.
You should set the Node n's previous Node's next field to NULL when n is the tail Node.

C++ Linked list implementation crashing

I am trying to implement a linked list for a data structures class and I am having some difficulty with the searching portion of the algorithm.
Below is the offending code, which I have tried to implement following the pseudo-code in the MIT introduction to algorithms text:
//
// Method searches and retrieves a specified node from the list
//
Node* List::getNode(unsigned position)
{
Node* current = m_listHead;
for(unsigned i = m_listSize-1; (current != 0) && (i != position); --i)
current = current->next;
return current;
}
The head at this point in the program is the 4th node, which contains the value of int 5. the problem appears to be in the body of the for-loop, where the pointer to the node object is assigned to the next node. But this is going beyond the head of the node, so it is essentially pointing at some random location in memory (this makes sense).
Shouldn't the algorithm be moving to the previous Node instead of the next Node in this case? Below is the pseudo-code:
LIST-SEARCH(L, k)
x <- head
while x != NIL and key != k
do x <- next[x]
return x
Also, here is the header file for my Linked list implementation. I haven't tried to implement it in Template form yet just to keep things simple:
#ifndef linkList_H
#define linkList_h
//
// Create an object to represent a Node in the linked list object
// (For now, the objects to be put in the list will be integers)
//
struct Node
{
// nodes of list will be integers
int number;
// pointer to the next node in the linked list
Node* next;
};
//
// Create an object to keep track of all parts in the list
//
class List
{
public:
// Contstructor intializes all member data
List() : m_listSize(0), m_listHead(0) {}
// methods to return size of list and list head
Node* getListHead() const { return m_listHead; }
unsigned getListSize() const { return m_listSize; }
// method for adding a new node to the linked list,
// retrieving and deleting a specified node in the list
void addNode(Node* newNode);
Node* getNode(unsigned position);
private:
// member data consists of an unsigned integer representing
// the list size and a pointer to a Node object representing head
Node* m_listHead;
unsigned m_listSize;
};
#endif
Implementation of addNode method:
//
// Method adds a new node to the linked list
//
void List::addNode(Node* newNode)
{
Node* theNode = new Node;
theNode = newNode;
theNode->next;
m_listHead = theNode;
++m_listSize;
}
Try this to construct the list:
void List::addNode(int number)
{
newNode = new Node;
newNode -> number = number;
newNode -> next = m_listHead ;
m_listHead = newNode;
++m_listSize;
}
It will add nodes to the head. Perhaps you may wish to store the pointer to the tail and insert the nodes there.
Unfortunately your code doesn't resemble the pseudo code you supply.
The pseudo-code is for searching a linked-list for a key, not a position.
The pseudo code reads as:
Assign head to (node) x.
while x isn't null and the key inside the current node (x) doesn't match k
assign x->next to x
return x
The returned value is either a pointer to the node that contains k or null
If you're trying to find the node at a given position your loop would be (note this is assuming you're going to use a zero-based index for accessing the list):
Assign head to (node) x
assign 0 to (int) pos
while x isn't null and pos not equal to given position
assign x->next to x
increment pos
return x
The result will either be a pointer to the node at the given position or null (if you hit the end of the list first)
Edit: Your code is very close to the latter if that's what you're trying to do ... can you see the difference?
Edit because I like homework where the OP asks the right questions :)
Node* List::getNodeContaining(int searchValue)
{
Node* current = m_listHead;
while (current != 0 && current->number != searchValue)
{
current = current->next;
}
return current;
}
Node* List::getNodeAtPos(int position)
{
Node* current = m_listHead;
int pos = 0;
while (current != 0 && pos != position)
{
current = current->next;
pos++;
}
return current;
}
You list is very different from what a normal list ADT looks like. Rather than returning nodes, which would require the client know about the list implementation, you return and accept the type you're making a list of.
In this case you're making a list of integers, sou you'd want
public:
void add(int num); //prepends an Item to the list
int get(int pos);
The implementations of both are simple. Add makes a new node, and links it in;
void List::add(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
m_listHead = newNode;
m_listSize++;
}
Then get is easy too:
int List::get(int pos)
{
if(pos>m_listSize)
;//throw an error somehow
Node *tmp = m_listHead;
while(pos-->0)
tmp=tmp->next;
return m->number
}