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;
}
Related
I've run it many times. I tried fixing my deleteNode() and addNode(), but it did not work. The output showed me that it failed to add some valid entries in my list, which resulted in failing to delete these valid entries. Someone please help me find the errors... I think either my isEmpty() is wrong or the addNode got messed up.
// Add nodes and makes it work in any cases: backward/forward
bool LinkedList::addNode(int id, string str) {
bool result = false;
if (id >= 0 && !(idExists(id))) {
Node *current = head;
Node *temp = new Node;
temp->data.data = str;
temp->data.id = id;
temp->forward = NULL;
temp->back = NULL;
// Kinds of adding cases
if(head == NULL) { // Check if list is empty
addHead(temp, current);
result = true;
} else {
while(temp->data.id > current->data.id && current->forward != NULL) {
current = current->forward;
}
// Backward
if(current->back == NULL) {
if(temp->data.id > current->data.id) {
if(current->forward == NULL) {
addTail(temp, current);
} else {
addMiddle(temp, current);
}
} else {
addHead(temp, current);
}
result = true;
// Forward
}else if(current->forward == NULL) {
if (temp->data.id > current->data.id) {
addTail(temp, current);
} else {
addMiddle(temp, current);
}
result = true;
}else {
if(temp->data.id > current->data.id) {
addMiddle(temp, current);
result = true;
}
}
}
}
return result;
}
void LinkedList::addHead(Node *temp, Node *current) {
if (head != NULL){
temp->forward = current;
current->back = temp;
head = temp;
} else {
head = temp;
}
}
void LinkedList::addMiddle(Node *temp, Node *current) {
temp->forward = current;
temp->back = current->back;
current->back->forward = temp;
current->back = temp;
}
void LinkedList::addTail(Node *temp, Node *current) {
current->forward = temp;
temp->back = current;
}
// Delete list
bool LinkedList::deleteNode(int id){
bool result = false;
if (idExists(id)) {
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
if (current->data.id == id && current->forward == NULL) {
if (current->back == NULL) { // Delete head
delete current;
head = NULL;
} else { // delete tail
deleteTail(current);
}
result = true;
} else if (current->data.id == id) {
if (current->back == NULL)
deleteHead(current);
else // delete middle
deleteMiddle(current);
result = true;
}
}
return result;
}
// Helper delete functions
void LinkedList::deleteHead(Node *current) {
head = current->forward;
head->back = NULL;
delete current;
}
void LinkedList::deleteMiddle(Node *current) {
current->back->forward = current->forward;
current->forward->back = current->back;
delete current;
}
void LinkedList::deleteTail(Node *current) {
current->back->forward = NULL;
delete current;
}
bool LinkedList::getNode(int id, Data *data) {
bool didGetNode = false;
if (idExists(id)) {
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
data->id = current->data.id;
data->data = current->data.data;
didGetNode = true;
}
return didGetNode;
}
// Check whether or not the id exists
bool LinkedList::idExists(int id){
bool exists = false;
if (head != NULL){
Node *current = head;
while (current->forward != NULL && current->data.id != id) {
current = current->forward;
}
if (current->data.id == id) {
exists = true;
}
}
return exists;
}
You probably want to be passing a pointer to a pointer (**) or a pointer to a reference (*&) in functions where you are wanting to make a change to what the address of the node is containing. I hope that this helps you visualize it.
For example:
struct Node { };
void setNull1(Node* temp)
{
temp = nullptr;
}
void setNull2(Node** temp)
{
(*temp) = nullptr;
}
void setNull3(Node*& temp)
{
temp = nullptr;
}
int main()
{
Node* tmp = new Node;
setNull1(tmp);
if (tmp == nullptr)
{
cout << "NULLPTR";
} // tmp is not nullptr
Node* tmp1 = new Node;
setNull2(&tmp1);
if (tmp1 == nullptr)
{
cout << "NULLPTR";
} // tmp1 is nullptr
Node* tmp2 = new Node;
setNull3(tmp2);
if (tmp2 == nullptr)
{
cout << "NULLPTR";
} // tmp2 is nullptr
}
You should also consider writing nullptr instead of NULL.
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;
This problem is a little more complicated than previous ones I've brought here, so I'll try to be very explicit about what I've narrowed it down to.
I'm writing a Binary Search Tree data class in C++ that functions like a standard BST except that it stores duplicates of Odd numbers using a "count" field in the BST node.
I've written a test driver to test the member functions of the class and have run into an error that I cannot seem to solve. When I attempt to add a set number of random integers to a BST object none of them seem to make it into the tree. To check the contents I use a printInOrder function that I have confirmed works properly so I know the problem isn't there.
For starters, I'll post the addLeaf, printInOrder, and createLeaf functions, and the small block of code where I call them in my driver file.
bool fixedDupBST::addLeaf(int key)
{
if(root == nullptr){
root = createLeaf(key);
assert(root != nullptr);
}
else {
node *prev = nullptr;
node *scanPtr = root;
bool right, dupe = false;
while(scanPtr != nullptr) {
prev = scanPtr;
if(key < scanPtr->key) {
scanPtr = scanPtr->left;
right = false;
}
else if (key == scanPtr->key) {
if (scanPtr->keyCount >= 1)
dupe = true;
else{
dupe = false;
scanPtr = nullptr;
}
}
else {
scanPtr = scanPtr->right;
right = true;
}
}
if (dupe)
prev->keyCount++;
else if (!dupe)
return false;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
}
return true;
}
fixedDupBST::node* fixedDupBST::createLeaf(int key)
{
node* newNode = new node;
assert(newNode != nullptr);
newNode->key = key;
newNode->left = nullptr;
newNode->right = nullptr;
if (key % 2 != 0)
newNode->keyCount = 1;
else
newNode->keyCount = 0;
return newNode;
}
void fixedDupBST::printInOrder()
{
printInOrderPr(root);
}
void fixedDupBST::printInOrderPr(node* Ptr)
{
if(root != nullptr) {
if(Ptr->left != nullptr){
printInOrderPr(Ptr->left);
}
cout << Ptr->key << ' ';
if(Ptr->right != nullptr) {
printInOrderPr(Ptr->right);
}
}
else {
cout << "The tree is empty" << endl;
}
return;
}
void testInsert(fixedDupBST &BST)
{
int temp;
for (int i = 0; i < TEST_PARAM; i++) {
temp = randNum();
BST.addLeaf(temp);
}
BST.printInOrder();
return;
}
The problem I'm getting is that when I call printInOrder() it always gives "The tree is empty". At first I thought it might be a problem with how I was passing parameters in the class member functions (pass by references vs pass by value) but that didn't provide any solutions. If there are any problems at all with the rest of the function it doesn't seem to matter because root never gets assigned to that first node, (hence why print in order just says "the tree is empty".
I need a second set of eyes on this; thanks in advanced for you help, and let me know if I can rephrase my question or provide more information to help make the situation clearer.
EDIT: R Sahu had the error correct, but his answer is a little off. I realized that a bool wouldn't work cleanly for what I was trying to do because there are actually 3 cases:
The number is a duplicate and is odd,
the number is a duplicate and is even
and the number is NOT a duplicate.
The problem stemmed from the fact that the quit condition for the while loop was scanPtr being null, and the if/else-if statement at the end had no way of knowing if it was null because it reached the end of a subtree and was ready to insert, or if I had manually set it to null upon finding a duplicate in order to break the loop appropriately.
Here is the solution I came up with.
bool fixedDupBST::addLeaf(int key)
{
if(root == nullptr){
root = createLeaf(key);
assert(root != nullptr);
}
else {
node *prev = nullptr;
node *scanPtr = root;
bool right;
int dupe = 0; // switch variable
while(scanPtr != nullptr) {
prev = scanPtr;
if(key < scanPtr->key) {
scanPtr = scanPtr->left;
right = false;
}
else if (key == scanPtr->key) {
if (key % 2 != 0) {
dupe = 1;
scanPtr = nullptr;
}
else{
dupe = 2;
scanPtr = nullptr;
}
}
else {
scanPtr = scanPtr->right;
right = true;
}
}
if (dupe == 2)
return false;
if (dupe == 1)
prev->keyCount++;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
}
return true;
}
Everything works appropriately now.
You have a logic error in this block.
if (dupe)
prev->keyCount++;
else if (!dupe) // This is pointless
// dupe is either true or false.
// Your code will never get to the next "else if"
return false;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
What you need is:
if (dupe) {
prev->keyCount++;
return false; // I think you want to return false here but I am not sure
}
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
R Sahu had the error correct, but his answer is a little off. I realized that a bool wouldn't work cleanly for what I was trying to do because there are actually 3 cases:
1: The number is a duplicate and is odd.
2: the number is a duplicate and is even.
3: the number is NOT a duplicate.
The problem stemmed from the fact that the quit condition for the while loop was scanPtr being null, and the if/else-if statement at the end had no way of knowing if it was null because it reached the end of a subtree and was ready to insert, or if I had manually set it to null upon finding a duplicate in order to break the loop appropriately.
Here is the solution I came up with.
bool fixedDupBST::addLeaf(int key)
{
if(root == nullptr){
root = createLeaf(key);
assert(root != nullptr);
}
else {
node *prev = nullptr;
node *scanPtr = root;
bool right;
int dupe = 0; // switch variable
while(scanPtr != nullptr) {
prev = scanPtr;
if(key < scanPtr->key) {
scanPtr = scanPtr->left;
right = false;
}
else if (key == scanPtr->key) {
if (key % 2 != 0) {
dupe = 1;
scanPtr = nullptr;
}
else{
dupe = 2;
scanPtr = nullptr;
}
}
else {
scanPtr = scanPtr->right;
right = true;
}
}
if (dupe == 2)
return false;
if (dupe == 1)
prev->keyCount++;
else if (right) {
prev->right = createLeaf(key);
assert(prev->right != nullptr);
}
else {
prev->left = createLeaf(key);
assert(prev->left != nullptr);
}
}
return true;
}
Everything works appropriately now.
I have been stuck on this function to remove node from a list, if there are two names in the list they are both gone. If Anne and John are in the list and I want to delete Anne, then my list is empty, John is gone.
What am I missing to keep the connection in the list if I delete a node init?
bool ContactList::remove(string key)
{
NodePtr prev = NULL;
for(NodePtr temp = head; temp != NULL; temp = temp->link)
{
if(temp->data.key == key)
{
if(prev == NULL)
{
head = temp->link;
delete temp;
return true;
}
else
{
prev = temp->link;
delete temp;
return true;
}
}
}
return false;
}
You aren't keeping prev up to date in every iteration of your loop. You want something like:
prev = temp;
at the bottom of your for loop.
Try using this function
bool ContactList::remove(string key)
{
NodePtr prev = NULL;
for(NodePtr temp = head; temp != NULL; temp = temp->link)
{
if(temp->data.key == key)
{
if(prev == NULL)
{
head = temp->link;
delete temp;
return true;
}
else
{
prev->link = temp->link; // change.
delete temp;
return true;
}
}
prev = temp; // change.
}
return false;
}
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);
}