storing c++ linked lists pointers in a vector - c++

I want to create a number of lists and store a pointer to each of the lists in a vector.
That i achieved but my problem is accessing the list in certain functions.
I have a function that checks the order in which the nodes are linked and invalidates certain lists based on their order. The function bool isValid() does the invalidation.
bool Train::isValid() const
{
Car* curr;
Car* temp;
Car* Fin;
Car* MVP;
bool result;
curr = m_head->getNext();
while(curr != NULL)
{
temp = curr->getNext();
Fin = temp->getNext();
MVP = Fin->getNext();
if((curr->getCargo()==3)&&(temp->getCargo()==2)||(curr->getCargo()==2)&&(temp->getCargo()==3))
result = false;
else if((curr->getCargo()==3)&&(temp->getCargo()==3)&&(Fin->getCargo()==3))
result = false;
else if((curr->getCargo()==0)&&(temp->getCargo()==0)&&(Fin->getCargo()==0)&&(MVP->getCargo()==0)&&((Fin->getNext())->getCargo()==0))
result = false;
else if((curr->getCargo()==4)&&(temp->getCargo()==0)&&(Fin->getCargo()==4))
result = false;
else
result = true;
curr = curr->getNext();
}
return result;
}
The code section below is where I am accessing the vector elements.
for(unsigned int i = 0; i<Vec.size();i++)
{
cout<<i+1<<": "<<*Vec.at(i)<<endl;
}
typ = Vec.at((A/1111)-1)->Stringconverter(REMOVE);
Vec.at((A/1111)-1)->removeCar((CARGO_TYPE)typ);
for(unsigned int i = 0; i<Vec.size();i++)
{
bool N = Vec.at(i)->isValid();
if(N)
cout<<i+1<<": "<<*Vec.at(i)<<"(valid)"<<endl;
else
cout<<i+1<<": "<<*Vec.at(i)<<"(invalid)"<<endl;
}
The part where I am caliing the function isValid()

Thanks for the insights, really helped.
This is the new functional code
bool Train::isValid() const
{
Car* curr;
Car* temp;
Car* Fin;
Car* MVP;
bool result;
//Setting current node to the head node's next, head node will always be a locomotive, hence not involved.
curr = m_head->getNext();
//If any of the condition returns false, the loop should break.
while(curr != NULL)
{
temp = curr->getNext(); //Setting first trail node to the current node's next
if(temp != NULL)
{
Fin = temp->getNext(); //Setting second trail node to the first trail node's next
//Condition for combustible car being next to a oxidizer car
if((curr->getCargo()==3)&&(temp->getCargo()==2)||(curr->getCargo()==2)&&(temp->getCargo()==3))
{
result = false;break;
}
else
result = true;
if(Fin != NULL)
{
MVP = Fin->getNext(); //Setting third trail node to the second trail node's next
//Condition for three combustible cars being in a row
if((curr->getCargo()==3)&&(temp->getCargo()==3)&&(Fin->getCargo()==3))
{
result = false;break;
}
//Condition for a radioactive car being next to a biological car
else if((curr->getCargo()==4)&&(temp->getCargo()==0)&&(Fin->getCargo()==4))
{
result = false;break;
}
else
result = true;
if(MVP != NULL)
{
//Condition for five biological cars being in a row
if((curr->getCargo()==0)&&(temp->getCargo()==0)&&(Fin->getCargo()==0)&&(MVP->getCargo()==0)&&((Fin->getNext())->getCargo()==0))
{
result = false;break;
}
else
result = true;
}
}
}
//moving current node to its next
curr = curr->getNext();
}
return result;
}

There is definitely a bug in your code:
while(curr != NULL) // NULL!! (the language supports nullptr)
{
temp = curr->getNext();
// Do not check `temp` is not nullptr before calling getNext()
Fin = temp->getNext();
// Do not check `Fin` is not nullptr before calling getNext()
MVP = Fin->getNext();
// Again in all the following (you don't check temp of Fin is not nullptr.
if((curr->getCargo()==3)&&(temp->getCargo()==2)||(curr->getCargo()==2)&&(temp->getCargo()==3))
result = false;
else if((curr->getCargo()==3)&&(temp->getCargo()==3)&&(Fin->getCargo()==3))
result = false;
else if((curr->getCargo()==0)&&(temp->getCargo()==0)&&(Fin->getCargo()==0)&&(MVP->getCargo()==0)&&((Fin->getNext())->getCargo()==0))
result = false;
else if((curr->getCargo()==4)&&(temp->getCargo()==0)&&(Fin->getCargo()==4))
result = false;
else
result = true;
curr = curr->getNext();
}
// The result is just the value from the last iteration of the above
// loop. The last iteration of the above loop curr is valid but
// curr->getNext() returns nullptr so temp is nullptr.
// Thus the call temp->getNext() has undefined value.
// So the value of result is completely unknowable.
return result;

Related

Segmentation Fault after calling method exists()

I'm having trouble manipulating a doubly linked list. I'm pretty sure I have my addNode(), getCount(), printList(), and getNode() working fine, but when executing, I get to right around my exists() and deleteNode() methods and I get a segmentation fault. exists() checks to see if a specific node exists, and deleteNode() passes in an id, and if the id matches a node id, it deletes that node. I don't know which method is messing up. Here are both of them. This is also my first post so if it's confusing and not thorough I apologize in advance.
bool LinkedList::deleteNode(int id){
bool didDelete = false;
bool hasResult = false;
Node *position;
position = head;
while(position!=NULL && !hasResult){
if(id == position->data.id){
hasResult = true;
} else {
std::cout << "position->next" << std::endl;
position = position->next;
}
}
// Deletes head node
if (position->prev == NULL) {
head = head->next;
head->prev = NULL;
delete (position);
didDelete = true;
}
// Deletes middle node
else if (position->next != NULL) {
position->prev->next = position->next;
position->next->prev = position->prev;
position->next = NULL;
position->prev = NULL;
delete(position);
didDelete = true;
}
// Deletes the tail node
// else if(position->next == NULL){
else{
position->prev->next = NULL;
position->prev = NULL;
delete(position);
didDelete = true;
}
return didDelete;
} // End of deleteNode
bool LinkedList::exists(int id){
Node *position;
position = head;
bool gotNode = false;
while (position != NULL && !gotNode) {
if(id == position->data.id){
gotNode = true;
} else{
position = position->next;
}
}
return gotNode;
} // End of exists
Your exists() is fine, though it can be simplified a little:
bool LinkedList::exists(int id){
for(Node *position = head; position; position = position->next) {
if (id == position->data.id) {
return true;
}
}
return false;
}
Your deleteNode() is broken, though. If the specified id is not found by the while loop, position will end up NULL, and the subsequent access to position->prev will invoke undefined behavior.
It is also needlessly verbose, it can be greatly simplified:
bool LinkedList::deleteNode(int id){
for(Node *position = head; position; position = position->next){
if (id == position->data.id){
if (position->next) position->next->prev = position->prev;
if (position->prev) position->prev->next = position->next;
if (position == head) head = head->next;
/* uncomment this if you ever add such a field...
if (position == tail) tail = tail->prev;
*/
delete position;
return true;
}
}
return false;
}

Debugging large text files taking too much time

I created a data bag structure. I read the text of a file and convert to lexicographical order. In order to do this I have to convert two string to lower case to compare them(One for the current node and one for the node that is next to it). But my problem is when I have big text files, it has to keep converting the string to lower case for each node I insert and sometimes it takes a long time to process. I was wondering if there are any ways better ways of adjusting this so I can increase the performance time.
void insert(string v)
{
if(head == NULL){ //empty list
head = new BagNode;
head->dataValue = v;
//head->dataCount = 0;
head->next = NULL;
}
else
{
BagNode * n = new BagNode; // new node
n->dataValue = v;
BagNode * current = head; //for traversal
//current = head;
n->dataCount = 0;
if(!isBefore(current->dataValue, v)) //new head
{
n->next = head;
head = n;
}
else{ //mid and tail insert
while(current->next && isBefore(current->next->dataValue,v))
{
current = current->next;
}
n->next = current->next;
current->next = n;
}
}
}
Compare Two Nodes
bool isBefore(string a, string b)
{
transform(a.begin(), a.end(), a.begin(), ::tolower);
transform(b.begin(), b.end(), b.begin(), ::tolower);
if(a == b) {
return true;
}
else {
return false;
}
}
I would remove the repeated calls to transform like this:
void insert(string v)
{
transform(v.begin(), v.end(), v.end(), ::tolower);
if(head == NULL){ //empty list
head = new BagNode;
head->dataValue = v;
//head->dataCount = 0;
head->next = NULL;
}
else
{
BagNode * n = new BagNode; // new node
n->dataValue = v;
BagNode * current = head; //for traversal
//current = head;
n->dataCount = 0;
if(!isBefore(current->dataValue, v)) //new head
{
n->next = head;
head = n;
}
else{ //mid and tail insert
while(current->next && isBefore(current->next->dataValue,v))
{
current = current->next;
}
n->next = current->next;
current->next = n;
}
}
}
bool isBefore(string a, string b)
{
if(a == b) {
return true;
}
else {
return false;
}
}
You can see some addition information on transform here. This suggestions that transform is loop over your range. A way to find something like this would be compile with -pg flags on GCC. This will enable profiling and you would see a hotspots with the functions isBefore and transform.

Array getting passed incorrectly to a function in C++

I'm working a project for class that requires creating a binary search tree of criminal names with up to 8 attributes per criminal.
I set up a string array att[] that will read in the attributes for each criminal, and then be passed to my BSTInsert class function. Through debugging I can see that the array is correct when it's just in the setupTree function. Once it's passed to BSTInsert, instead of having each string it only has one string, and on top of that nothing is copied from the array to the node in the tree.
Can anyone tell me what I'm doing wrong?
Here's my code for setting up the tree:
void setupTree(BST& criminals)
{
ifstream fin("criminals.txt");
string temp;
fin >> temp;
//FINISHED means it has all the criminals
while (temp != "FINISHED")
{
//SUSPECT lets it know to read in a new name and new attributes
if (temp == "SUSPECT")
{
string name;
string att[8];
int count = 0;
fin >> temp;
//if there is a false "suspect" line, quit
if (temp == "FINISHED") return;
name = temp;
fin >> temp;
while (temp != "SUSPECT" && temp != "FINISHED")
{
att[count] = temp;
count++;
fin >> temp;
}
criminals.BSTInsert(name, att, count);
}
}
}
Here's my class function for inserting a node:
bool BST::BSTInsert(treetype name, treetype att[], int count)
{
//gets the memory for the node. If unable, returns fail.
node* newNode = new node;
if (newNode == NULL)
{
return false;
}
newNode->count = 0;
//initializes the node with the given information to place
for (int i = 0; i < count; i++)
{
newNode->att[newNode->count] = att[count];
newNode->count++;
}
newNode->name = name;
newNode->left = newNode->right = NULL;
//if the tree is empty, creates this node as the root
if (root == NULL)
{
root = newNode;
root->parent = NULL;
}
else
{
//the tree is not empty, so it will use the parent to insert the node
node* current = root;
node* parent = NULL;
//finds the insertion spot
while (current != NULL)
{
parent = current;
if (name <= current->name)
{
current = current->left;
}
else
{
current = current->right;
}
}
//inserts the new node onto the correct side of the parent
if (name <= parent->name)
{
parent->left = newNode;
}
else
{
parent->right = newNode;
}
newNode->parent = parent;
}
return true;
treetype att[] doesn't pass an array, it passes a pointer to an array - it decays to treetype att*.
That said, your problem is here:
for (int i = 0; i < count; i++)
{
newNode->att[newNode->count] = att[count];
newNode->count++;
}
This copies the wrong element of att (beyond the end of the array) into every att in newNode. What you meant was
for (int i = 0; i < count; i++)
{
newNode->att[newNode->count] = att[newNode->count];
newNode->count++;
}

Removing a node from a linked-list

I've created a Hash-table and I want to remove a node from the linked-list. The code works for removing the first node but not for removing others.
void intHashTable::remove(int num){
int location = ((unsigned)num) % size;
Node * runner = table[location];
int checker;
if(runner->next == NULL){
if(num == table[location]->num){
table[location] = NULL;
}
}else{
if(table[location]->num == num){
table[location] = table[location]->next;
}else{
//This part doesn't seem to be working.
Node *temp = runner->next;
while(temp != NULL){
if(temp->num == num){
runner->next = temp->next;
delete(temp);
break;
}
}
}
}
}
You haven't updated temp to point to the next item within the loop:
temp = temp->next;
You also appear to represent an empty row with a NULL pointer in your table, but you don't handle this case properly in your code - if runner is NULL then you'll crash when you try to access runner->next in the first check. Also, you're failing to delete the node in some cases.
To fix these issues, you can update your code to something like this:
void intHashTable::remove(int num)
{
int location = ((unsigned)num) % size;
Node * runner = table[location];
if (runner != NULL) {
if (runner->num == num) {
delete runner;
table[location] = NULL;
} else {
while (runner->next != NULL) {
if (runner->next->num == num) {
Node *temp = runner->next;
runner->next = runner->next->next;
delete temp;
break;
}
runner = runner->next;
}
}
}
}
Also note that I've removed the brackets from delete, which is a C++ keyword and not a function.
If you use doubly-linked lists (i.e. with a previous pointer as well as a next) then you can simplify this code a little, although for something like a hash table where you only tend to iterate through in one direction it's probably not worth the expense of the extra pointer (an extra 8 bytes per item on a 64-bit system).
You didn't updated temp and runner variables inside loop:
while(temp != NULL)
{
if(temp->num == num)
{
runner->next = temp->next;
delete temp;
break;
}
runner = temp; // Keep previous element to change its next pointer when num found
temp = temp->next; // Advance current pointer to next element
}

Linked list cstring insertion sort

This is my code for an insertion-sort, sorting via the cstring member of the node. The current code only inserts before the head. The code encapsulated in comments is the sorted insertion I am trying to make work. I'm thinking I have to use a predecessor and successor pointer, but maybe it's the comparison that is confusing me. Any help would be appreciated. Thanks!
#include <iostream>
#include "groclist.h"
void insert_item(Grocery_Item_Ptr &head, int quantity, const char name[])
{
bool exists = false;
bool done = false;
Grocery_Item_Ptr temp = NULL;
Grocery_Item_Ptr current = NULL;
Grocery_Item_Ptr pred = NULL;
Grocery_Item_Ptr succ = NULL;
if (head == NULL) {
head = new Grocery_Item;
head->quantity = quantity;
strncpy(head->name, name, MAX_ITEM_NAME_LEN);
head->next = NULL;
return;
}
else {
current = head;
while (current != NULL) {
if (strncmp(current->name, name, MAX_ITEM_NAME_LEN) == 0) {
current->quantity += quantity;
exists = true;
}
current = current->next;
}
if (exists) {
current = NULL;
return;
}
else {
current = head;
}
if (!exists) {
temp = new Grocery_Item;
temp->quantity = quantity;
strncpy(temp->name, name, MAX_ITEM_NAME_LEN);
/*
while (!done || current != NULL) {
if (strncmp(current->name, name, MAX_ITEM_NAME_LEN) < 0) {
pred = current;
succ = current->next;
current->next = temp;
temp->next = succ;
done = true;
}
if (!done) {
current = current->next;
}
}
*/
temp->next = head;
head = temp;
temp = NULL;
}
}
return;
}
One thing you are missing is keeping a reference to the predecessor while searching. This is necessary in order to keep the chain intact.
Here is a draft that should work (currently untested!):
while (!done || current != NULL)
{
//If we found the place to insert
if (strncmp(current->name, name, MAX_ITEM_NAME_LEN) < 0)
{
//If the place to insert was at head
if(pred == NULL)
{
//The new node becomes the head
head = temp;
}
else
{
//Set the previous nodes next to point at this node.
pred->next = temp;
}
//Always set the node to be inserted's next
//pointing to the node we should be inserted before
temp->next = current;
done = true;
}
if (!done)
{
//No match, keep looking but keep an updated pred pointer
pred = current;
current = current->next;
}
}
It's just pseudocode, but maybe it helps:
if(head == NULl)
{
//make newnode as head
}
if(head.name == new name)
{
//update quantity
}
if(head.name <new name)
{
//insert newnode before head
//make newnode as head
}
if (new name > head.name)
{
current = head;
succ = current.next;
while (succ && new name <succ.name)
{
curent = succ;
succ = succ.next
}
if(succ = NULL)
current->next = newnode
else
if new name = succ->name
update quantity
else
curent->next = newnode
newnode->next = succ;
}
I appreciate your input guys, if only for having me think about it in different ways. However my result is quite different, and I must truly thank my whiteboard.
if (strncmp(name, head->name, MAX_ITEM_NAME_LEN) < 0) {
temp->next = head;
head = temp;
temp = NULL;
}
else {
pred = head;
current = head->next;
do {
if (strncmp(name, current->name, MAX_ITEM_NAME_LEN) < 0) {
pred->next = temp;
temp->next = current;
done = true;
}
else if (current->next == NULL) {
current->next = temp;
done = true;
}
else {
pred = current;
current = current->next;
}
if (done) {
pred = NULL;
current = NULL;
}
} while (!done && current != NULL);
}