C++: While loop won't terminate as NULL, am I missing something? - c++

It seems that I can't figure out why the while loop wont terminate.
It should be while(null) essentially.
I can't figure it out.
All help would be appreciated :D
I dont know what could possibly be stopping the while loop at all? It says that the first entry gets stored, and the entry for next is at 0x0000000000 and ??? name and ??? ??? coords so it is in fact NULL. I tried adding in the constructor next = 0; instead of next = NULL and it still did not work.
Thanks guys.
Anthony
EDIT: Value of nodePtr = 00000000 if next = 0 in the constructor
Value of nodePtr = 00899FE0 if next = NULL in the constructor
if adding a cout << nodePtr->next; before the while.
http://pastebin.com/7usYdfHB -- Full program for reference.
EDIT2:
Is the popup when I go to enter the 2nd entry.
void LinkedList::appendNode(string name, double x, double y)
{
ListNode* newNode; // To point to new node
ListNode* nodePtr; // To traverse List
// allocate new node
newNode = new ListNode(name, x, y);
// If no head, head is the newNode
// else traverse the list to find the end and append newNode
if (!head)
{
head = newNode;
cout << "Record inserted successfully.\n" << endl;
}
else
{
nodePtr = head;
//traverse the list loop
while (nodePtr->next) //VS 2012 locks up here <-----
{
//Checks for duplicate entry by name
if (nodePtr->cityName == name)
{
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
return;
}
//traverse the list
nodePtr = nodePtr->next;
}
// checks 2nd entry, as while loop wont run for a 2nd entry.
if (nodePtr->cityName == name) {
{
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
return;
}
}
// if next is NULL add newNode
else if (!nodePtr->next)
{
nodePtr->next = newNode;
cout << "Record inserted successfully.\n" << endl;
}
}

Aside from the obvious memory leak when an attempt to insert an already existing name is made, your code seems to work fine. It works fine when either 0 or NULL is used to initialize the pointers. It makes no difference.
(One wild guess I can make is that in your actual calling code (which you do not show), you somehow managed to pass your LinkedList around by value. Since your LinkedList does not satisfy the Rule of Three, the integrity of the list got violated, which lead to undefined consequences you observed.)
BTW, by using an extra level of indirection you can simplify your heavily branched appendNode function into a significantly more compact and almost branchless one
void LinkedList::appendNode(string name, double x, double y)
{
ListNode** pnodePtr;
for (pnodePtr = &head; *pnodePtr != NULL; pnodePtr = &(*pnodePtr)->next)
if ((*pnodePtr)->cityName == name)
break;
if (*pnodePtr == NULL)
{
*pnodePtr = new ListNode(name, x, y);
cout << "Record inserted successfully.\n" << endl;
}
else
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
}
(I also eliminated the leak.) Specifically, this technique allows one to avoid writing a dedicated branch for processing the head node.
Also (referring to the full version of the code), in your functions from "delete by coordinate" group you for some reason check both x and y coordinates of the head node, but only one coordinate of the other nodes down the list. Why? This is rather weird and does not seem to make much sense. Meanwhile, functions from "search by coordinate" group do not have this issue - they process all nodes consistently.
Also, your displayList function suffers from a stray return at the very beginning, which is why it never prints anything. You need to add a pair of {} to properly group your statements.

I tried to reproduce your problem but could not. I reverse engineered your ListNode and LinkedList classes. The code below works, maybe that will help you sort out your issue. I refactored it a little to simplify it (going further you should consider keeping track of the end of the list as this will help with other operations that your list will need). Be sure to implement a destructor for your LinkedList class to clean up the nodes.
#include <string>
#include <iostream>
using namespace std;
struct ListNode
{
string cityName;
double m_x, m_y;
ListNode* next;
ListNode(string name, double x, double y) : cityName(name), m_x(x), m_y(y), next(nullptr)
{}
};
class LinkedList
{
ListNode* head;
public:
LinkedList() : head(nullptr)
{
}
~LinkedList()
{
}
void LinkedList::appendNode(string name, double x, double y)
{
ListNode* newNode; // To point to new node
// allocate new node
newNode = new ListNode(name, x, y);
// If no head, head is the newNode
// else traverse the list to find the end and append newNode
if (!head)
{
head = newNode;
cout << "Record inserted successfully.\n" << endl;
}
else
{
ListNode *nodePtr = head;
ListNode *prevNode = nullptr;
//traverse the list loop
while (nodePtr)
{
//Checks for duplicate entry by name
if (nodePtr->cityName == name)
{
cout << "No need to insert again, as this record exists in the existing data set.\n" << endl;
return;
}
//traverse the list
prevNode = nodePtr;
nodePtr = nodePtr->next;
}
// if next is NULL add newNode
if (prevNode)
{
prevNode->next = newNode;
cout << "Record inserted successfully.\n" << endl;
}
}
}
};
int main()
{
LinkedList list;
list.appendNode("New York", 1.0, 2.0);
list.appendNode("Boston", 1.5, 2.5);
list.appendNode("Miami", 1.7, 2.7);
list.appendNode("Miami", 1.7, 2.7);
}

Related

Improve my solution to basic C linked list management functions

I would appreciate some help relative to my code solution, which deals with linked list management in C. I'll already declare the only strange thing with my request: I am writing a C++ file, but I am actually mostly leveraging C resources (malloc(), free(), etc.); that said, given the basic code I provide, I am confident no one will have trouble with that.
I want to write a function to add elements to the end of the list and one to delete elements from it, that work in any edge case. Given my desire, the removal function was the one that I struggled the most with, but also the one that made me realize how little I am understanding pointers.
I will now share the code I produced, that should be working fine, but:
It can surely be greatly improved both in terms of clarity and performance
I think that showing it to the community will highlight many of the flaws present in my solution
// The plan is to create a linked list and to be able to add and delete its elements
#include <iostream>
using namespace std; // I can write output lines as cout << "Hi!", rather than std::cout < "Hi!"
#include <cstdlib> // needed for malloc() in C++
struct node {
int data;
node* nextPtr; //"struct node* nextPtr;" : This would be the syntax for plain old C: you always have to type the "struct" keyword
};
node* createElement(int data) {
node* newElemPtr = (node*)malloc(sizeof(node)); // the "(node*)" cast is required by C++, and is not used in C
newElemPtr->data = data;
newElemPtr->nextPtr = NULL;
return newElemPtr;
}
void appendElement(int data, node** head) { // Adds a new node at the end of the list
// I pass as argument a pointer to pointer (double pointer) to node, so that I can edit the head node
// if the list is empty, without having to return a new node pointer as head: my function indeed features
// "void" in its signature
node* elemPtr = NULL;
elemPtr = createElement(data); // elemPtr is a pointer to the new node
if (*head == NULL) {
*head = elemPtr;
}
else {
node* currPtr = *head; // currPtr is the temporary variable that visits each node of the linked list
while (currPtr->nextPtr != NULL)
currPtr = currPtr->nextPtr;
currPtr->nextPtr = elemPtr; // Set last element's nextPtr to "elem", i.e., a pointer to the new element
}
};
void removeElement(int data, node** head) { // Remove all the nodes whose data content matches the "data" argument
int presence_flag = 0; // Flag used to check whether the required data is present at all in the linked list
if (*head == NULL) {
return;
}
else {
node* currPtr = *head;
node* prevPtr = *head;
while (currPtr != NULL) {
// This is the case in which I find a node to delete (it matches the "data" query), and it is not the first of the list
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
// This is the case in which I find a node to delete and it is the first of the list
else if (data == currPtr->data && currPtr == *head) {
// This is the case in which I have to delete the first node, but the list features other nodes
if (currPtr->nextPtr != NULL){
*head = currPtr->nextPtr; // Move *head forward
currPtr = *head; // Do the same with currPtr, in order not to break the while() loop
free(prevPtr); // As *head has already been re-assigned, I leverage prevPtr to delete the old *head
presence_flag = 1;
}
// This is the case in which I have to delete the first and only node of the list
else {
*head = NULL;
currPtr = *head;
presence_flag = 1;
}
}
// This is the case in which the current node does not match the queried "data" value
else{
prevPtr = currPtr; // Update prevPtr
currPtr = currPtr->nextPtr; // Move currPtr forward
}
}
}
if (presence_flag == 0)
cout << "There is not any node with value " << data << " in the linked list.\n\n";
// Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
// Q2: Should I free() everythin before ending the main(), at least as a good practice?
// Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value?
// Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
};
void printLinkedList(node* head) { // Here I return nothing, so I can freely edit "head" (i.e., there is no need for a temporary pointer)
if (head == NULL) {
cout << "The linked list is empty.\n";
}
else {
int elemCounter = 0;
while (head != NULL) {
elemCounter += 1;
cout << "elem N. " << elemCounter << ": data value = " << head->data << "\n"; // head->data is equal to (*head).data
head = head->nextPtr;
}
}
};
int main(int argc, char* argv[])
{
//cout << "Size of a single node of the list = " << sizeof(node) << "\n";
// == 16. On a 64 bits machine, an int ("data") requires 4 bytes.
// The pointer requires 8 bytes; the remaining 4 bytes are padding
node* head = NULL;
appendElement(1, &head);
appendElement(2, &head);
appendElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 3...\n\n";
removeElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 4...\n\n";
removeElement(4, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
return 0;
}
As you can see from the comments embedded in the code, I have 3 doubts that captured my interest while coding the node removal function:
Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
Q2: Should I free() everything before ending the main(), at least as a good practice?
Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value? Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
I hope that featuring these "additional" questions is something reasonable to put here, as maybe someone in the future may have the same doubts I had.
I know there are plenty of ready-to-copy-and-paste solutions for my task, but I think I can really learn this stuff if I see why my precise design choices are not optimal/wrong.
I thank everyone for the time spent reading this.
There are many duplicated code. Also the function should not output any message. It is the caller of the function that decides whether to output a message. So the function should have the return type bool if you are considering the program as a C++ program or bool or int if you are considering the program as a C program.
The function removeElement invokes undefined behavior because in its paths of execution you are not always resetting correctly values of the pointers currPtr and prevPtr after deleting a node.
For example after this code snippet
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
prevPtr and currPtr will be equal each other.
I would define the function the following way
int removeElement( node **head, int data )
{
int deleted = 0;
while ( *head )
{
if ( ( *head )->data == data )
{
deleted = 1;
node *current = *head;
*head = ( *head )->next;
free( current );
}
else
{
head = &( *head )->next;
}
}
return deleted;
}
As for your question
Q3: Is there a way to make this function by not using a double pointer
as input and by also keeping "void" as return value? Of course, it
should still work in the tricky edge case of the last element in the
list that has to be deleted
then in C you can not achieve this. In C++ you can pass the pointer to the first node by reference. In C passing by reference means passing an object indirectly through a pointer to it. So in C you have to use a double pointer in such a case.
Of course just setting a pointer to NULL without freeing data pointed to by the pointer that was dynamically allocated produces a memory leak. And you should free all the allocated memory then it is not required any more.

Last node is not printed in Linked List

I was trying to learn the Linked list and perform insertion operations from beginning of the list. while printing the nodes, the first node is not printed. Here is the core functions which I have written. Can someone help me?
struct Node //basic structure for a node
{
ll data; //data which we want to store
Node* link; //address of the next node;
};
Node* head=NULL;
void Insert(ll x) //insertion at beginning
{
Node* temp=new Node();
temp->data=x;
temp->link=head; //we are linking new node with previously connected node
head=temp;
}
void Print()
{
Node* temp=head;
while(temp->link!=NULL) //traversing the list until last element(last element.link = NULL)
{
cout<<temp->data<<" ";
temp=temp->link;
}
cout<<endl;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
f(i,0,5)
{
ll x;cin>>x;
Insert(x);
}
Print();
return 0;
}
Your Print function requires that the last node is linked or it won't be printed. Since the last node is never linked, it will never be printed.
void Print()
{
Node* temp = head;
while(temp) // <- corrected condition
{
std::cout << temp->data << ' ';
temp = temp->link;
}
std::cout << '\n';
}
It's because of your check in the while. The node will have link set as NULL, and therefore it will exit the while without printing it. My recommendation is changing the while check to (temp != NULL), but you can also fix it by putting a cout << temp->data; after the loop
In general the function Print can invoke undefined behavior when it is called for an empty list due to the expression temp->link that uses a null pointer to access memory.
Another side effect is that the last node will be skipped due to the condition in the while loop (if the list has only one node then its value will not be outputted)
while(temp->link!=NULL)
The function can be declared and defined the following way
std::ostream & Print( std::ostream &os = std::cout )
{
for ( const Node *current = head; current != nullptr; current = current->next )
{
os << current->data << " -> ";
}
return os << "null";
}
And in main the function can be called like
Print() << '\n';
The function is flexible. You can use it to write data in a file providing a corresponding file stream.
The function Insert can be simplified the following way
void Insert( ll x ) //insertion at beginning
{
head = new Node { x, head };
}
Pay attention to that it is a bad idea to declare the pointer head in the global namespace. In this case all functions depend on the global variable and you can not for example to use two lists in your program.
So you should declare the pointer in main.
int main()
{
Node *head = nullptr;
//...
In this case for example the function Insert can look the following way
void Insert( Node * &head, ll x ) //insertion at beginning
{
head = new Node { x, head };
}
and called in main like
Insert( head, x );

C++ Singly Linked List Insertion Sort

So hey, I'm having a problem with this project I have. I'm supposed to read integers from a file and insert them into a list. There's a findSpot function that needs to be implemented that traverses the linked list and if the next node's value is larger than what is being checked, it returns the current "spot". And then we output the linked list to a separate file.
Here's the code.
#include <iostream>
#include <fstream>
using namespace std;
class listNode {
public:
int value;
listNode* next;
friend class linkedList;
listNode()
: value(0)
, next(NULL)
{
}
public:
~listNode(){
};
};
class linkedList {
listNode* listHead;
public:
linkedList()
: listHead(NULL)
{
}
bool isEmpty()
{
return (listHead == 0);
}
void listInsert(int data, listNode* spot)
{
listNode* newNode;
newNode->value = data;
newNode->next = NULL;
if (isEmpty()) {
listHead = newNode;
}
else {
newNode->next = spot->next;
spot->next = newNode;
cout << newNode;
}
}
/*void listDelete ()
{
}*/
listNode* findSpot(int data)
{
listNode* spot;
spot = listHead;
while (spot->next != 0 && spot->next->value < data) {
spot = spot->next;
}
return spot;
}
void printList(listNode* spot)
{
listNode* newNode = spot;
while (newNode != NULL) {
cout << "Inserting " << newNode->value << ": "
<< "listHead-->(" << newNode->value << "," << newNode->next->value << ")-->(";
newNode = newNode->next;
}
cout << endl;
}
/*~linkedList()
{
listNode* temp = spot->next;
spot->next = spot->next->next;
delete temp;
}*/
};
int main(int argc, char* argv[])
{
int data;
listNode* spot;
ifstream infile;
infile.open(argv[1]);
ofstream outfile(argv[2]);
cout << "Reading Data from the file" << endl;
while (infile >> data) {
cout << data << endl;
}
infile.close();
linkedList myList;
infile.open(argv[1]);
while (infile >> data) {
myList.findSpot(data);
myList.listInsert(data, spot);
myList.printList(spot);
}
cout << "Printing your linked list to the output file.";
/*while (outfile.is_open())
{
myList.printList();
}*/
infile.close();
outfile.close();
return 0;
}
I don't know if the problem lies mainly in the insertList function or if it's the findSpot function. The findSpot function seems correct to me but I may just be missing something.
As I run the code, the actual reading of the file the first time is fine. Actually inserting anything into the linked list causes the program to hang.
Ok, lets try this again. I'll actually include some code, but please try to use this as a learning point, and not something to just copy paste. I know you said you were copying your teachers algorithm, but what they gave you is probably just that, an algorithm. It is your job to actually implement that in working code, checking for error conditions, etc. Anyway, here we go:
For the function findSpot:
listNode* linkedList::findSpot(int data) {
listNode* spot = listHead; // Initialize spot to start of list
if ( isEmpty() ) // if list is empty, return NULL
return NULL;
// now we know listHead isn't null, so look through the list and
// find the entry that has a value greater than the one provided
// return the list item BEFORE the one with the greater value
while (spot->next != 0 && spot->next->value < data) {
spot = spot->next;
}
// return the one we found; This could be the same as listHead
// (start of list), something in the middle, or the last item on the
// list. If we return from here, it will not be NULL
return spot;
}
Now we can do the insert function:
void linkedList::listInsert(int data, listNode* spot) {
// We need a new item to put on the list, so create it
listNode* newNode = new listNode();
newNode->value = data;
newNode->next = NULL;
// If the list is empty, update the head to point at our new object
if ( isEmpty() ) {
listHead = newNode;
// otherwise point spot to new item, and new item to the one spot
// pointed to
} else {
newNode->next = spot->next;
spot->next = newNode;
}
}
Looking at your print function, that is going to have it's own issues. It looks like you want to print the whole list, but it seems that you are starting to print from "spot". It's all very confused. It also has an issue using newNode->next->value, without checking if newNode->next is NULL. Here's a short example of what I think you are trying to do... note that I don't even need to pass in spot, just the data point added:
void linkedList::printList(int data) {
// if some huckleberry called this before calling insert,
// list will be empty... always a good idea to check
if ( isEmpty())
return;
// first line of output... just print out the data point
// added and start of output text
cout << "Inserted " << data << ": " << "listHead-->(";
// start at start of list
listNode* newNode = listHead;
// loop through until we find the end
while (newNode != NULL) {
cout << newNode->value; // print the value
newNode = newNode->next; // move to the next item on the list
// We moved to the next node; It might be NULL and the loop will end
// if not, we want to print an open bracket since we know another one
// is going to be printed
if ( newNode != NULL )
cout << ")-->(";
}
// last item was just printed, so close off the last bracket
cout << ")" << endl;
}
Hope that is somewhat helpful
Since this looks like a homework assignment, I'm going to give you one fix:
change
myList.findSpot(data);
to
spot = myList.findSpot(data);
If you look closely, spot is used, but never assigned anything.
Well, there are several problems with your program (besides formatting). In the function findSpot(), you have:
listNode* spot;
spot = listHead;
while (spot->next != 0 && spot->next->value < data) {
spot = spot->next;
}
return spot;
The problem here is that the first time you call this, listHead is NULL, so the
while (spot->next
is going to fail, since spot is NULL.
I also notice that nowhere in your code do you call new(). In listInsert, you need to use new() to initialize your newNode variable.
Lastly, find spot has 2 conditions where it can return NULL. If the list is empty, it should return NULL, and you would want to insert at the start of the list. If the new value you are adding is greater than all the others, you will also return NULL and you would have to add to the end of the list.
Since this is a homework assignment, I don't want to write the code for you, but hopefully that helps.

Linked list and dynamic allocation frustration c++

Here's the reference code:
#include <iostream>
using namespace std;
class linkedList {
struct listNode{ //a node of a list
int value;
struct listNode *next;
};
listNode *head;
public:
linkedList(){
cout << "hello1\n";
head = NULL;
};
linkedList(listNode* a){
cout << "hello2\n";
head = a;
};
~linkedList();
listNode* getHead() {return head;}
void appendNode(int);
//inline Search function due to unable to function outside of class definition
listNode* rangeSearch(int a, int b){
//listNode to search
listNode *search = head;
//listNode* toReturn = new listNode;
//listNode to return list of values that are found within range
linkedList *found = new linkedList;
while(search){
//if the current value is within range, then add to list
if(search->value >= a && search->value <= b){
//append searched value onto found
found->appendNode(search->value);
//after appending, go to next value
}
search = search->next;
}
return found->getHead();
}
void display();
};
int main()
{
cout << "Programmer : n\n";
cout << "Description : \n";
linkedList* list = new linkedList;
int x = 12;
//values to search
int s1 = 10, s2 = 14;
// adds 2 to each number on list for 5 times
for(int i = 0; i < 5; i++){
list->appendNode(x);
x += 2;
}
//create something to hold pointer of found to be deleted when done using
//print list
cout << "Original set of numbers in linked list: ";
list->display();
cout << "\nThe following are the values withing ranges: " << s1 << " and " << s2 << ":\n";
//EDITED:
//list->rangeSearch(s1,s2);
linkedList foundList(list->rangeSearch(s1,s2));
foundList.display();
//End of edit 6:40PM 7/18/13
cout << "\nHere are the original set of numbers in linked list (again): ";
list->display();
delete list;
return 0;
}
void linkedList::appendNode(int newValue)
{
listNode *newNode = new listNode(); // To point to a new node
listNode *nodePtr; // To move through the list
// Allocate a new node and store newValue there.
newNode->value = newValue;
newNode->next = 0;
// If there are no nodes in the list
// make newNode the first node.
if (!head)
head = newNode;
else // Otherwise, insert newNode at end.
{
// Initialize nodePtr to head of list.
nodePtr = head;
// Find the last node in the list.
while (nodePtr->next)
nodePtr = nodePtr->next;
// Insert newNode as the last node.
nodePtr->next = newNode;
}
}
void linkedList::display() {
for(listNode* p = head; p != NULL; p = p->next)
cout << p->value << ' ';
}
linkedList::~linkedList()
{
cout << "\ndestructor called";
listNode *nodePtr; // To traverse the list
listNode *nextNode; // To point to the next node
// Position nodePtr at the head of the list.
nodePtr = head;
// While nodePtr is not at the end of the list...
while (nodePtr != NULL)
{
// Save a pointer to the next node.
nextNode = nodePtr->next;
// Delete the current node.
delete nodePtr;
// Position nodePtr at the next node.
nodePtr = nextNode;
}
}
So a couple of questions here. First, why is it when I try to put the rangeSearch member function outside of the class definition, the compiler gives an error saying listNode* type is not recognized?
Second, this has to do with destructors. In this program, 2 instances (list & found list) were created but only 1 destructor was called. Can someone explain why? My intuition tells me that the dynamically allocated pointer to linkedList object did not get destructed. However, I don't know why. The reason I had to use dynamically allocated memory is primarily because I want to pass the pointer back to the main function. If I don't, when rangeSearch exits, the pointer will be passed back to main but whatever list the pointer had would be deconstructed after
return ptr; (assume ptr is a pointer to a linkedList declared in rangeSearch)
which will cause my program to crash because, now the address has nothing in it and I'm trying to call... nothing.
Well, as usual I would appreciate whoever the great Samaritan out there who would be more than willing to educate me more about this.
First, you are having an issue with scoping. In C++, the curly braces define a new scope, so you are defining listNode inside the class linkedlist. If you want to access it, you'd have to use the scoping operator as such linkedlist::listNode
I don't entirely understand your second question. I only see one call to delete, so why do you think two destructors will be called? The destructors are only called when you call delete, so unless you specify that you want to destroy it, it's still going to be there.
Although I don't entirely understand your question, I see that you returned a pointer to the head in rangeSearch, but you don't assign it to anything. What this means is that you will have a memory leak; you allocated memory for the found, but then don't do anything with it. Actually since you only return the head, you still wouldn't be able to delete it if you did assign something to it, because you wouldn't have access to linked list itself.
linkNode is nested inside of linkedList. Move listNode outside of the linkedList class, and you won't get the first error. Or you can use it's full declaration, linkedList::listNode. Also, if you leave linkNode nested, you will have to make it public.
In main, you can just say
linkedList list;
instead of
linkedList* list = new linkedList;
rangeSearch() is returning a value, but that value is never being assigned to anything in main(). rangeSearch() is allocating a linkedList, but it never gets deleted.

Deleting Node in Linked List C++

So I've been searching forums, but im still very new to the language and linked lists so I can barely decipher the results.
basically I made a delete function for my linked list.
I can currently Create a list, traverse the list, sort the list, search the list, and insert before any node in the linked list. I recycled some code from the insert to locate the point in the list where I could delete. My main point of confusion is how to link the previous points to the node that is after the one I am deleting.
I won't write a whole new linked list implementation but i can point out some of the problems with the code for you.
The trick is to stay one node ahead of the one you want to delete.
I have renamed entry to current for clarity
nodetype *current , *first, *next;
int akey;
// With this line your search will start from the second element.
// current =start->ptr;
// Should be
current = start;
// this is not needed. I am assuming the last node has NULL value for '->ptr'
// last=start;
next = current->ptr;
cout<<"Input Data You Would Like To Delete"<<endl;
cin>>akey;
// Check if the first node contains the data
// Assuming the list will have at least one element. i.e. current is not NULL
while (current->adata == akey)
{
// Delete it.
delete current;
// Update current for the while loop
current = next;
// update next too.
next = current->ptr;
}
// Now we know the first element doesn't contain the data.
// Update the pointer to the begging of the new list if anything is removed from the top.
first = current;
// This has unnecessary checks.
// ****Specifically (akey!=current->adata) will
// prevent you from entering the loop if it is false.
// while((akey!=current->adata)&&(current->ptr !=NULL))
while(next != NULL) // This should be enough
{
if(next->adata == akey)
{
// make the current node (before the 'deletion point')
// lined to the one after the 'deletion point (next of the next)
current->ptr = next->ptr;
// delete the node.
delete next;
// Make the next pointer point to the new next.
next = current->ptr
}
// Otherwise advance both current and next.
else {
current = next;
next = next->ptr;
}
}
// Use this to test it.
current = first;
while(current){
cout<<current->adata<<", ";
current = current->ptr;
}
This is not the cleanest way. However it is similar to your implementation so you can see where you went wrong.
#include <iostream>
#include <string>
// blank line(s) after includes
using namespace std; // some people will say to avoid this
// but I use it in examples for brevity
// blank line(s) around class def
class nodetype
{ // bracket on its own line
public: // non indented visibility specifier
nodetype(int value, nodetype *p) // constructor first declared in class
{
adata = value; // level of indentation for fn body
ptr = p; // spaces around operators like =
}
// blank line(s) between fns and vars
int adata;
nodetype *ptr;
};
// blank line(s) between class and fn
void LinkedListDelete(nodetype **start, int akey)
{
nodetype *current, **previous; // pointer *s are connected to vars
// blank line between section
previous = start;
current = *start;
// blank line between section
// I use blank lines a lot, they help
// me to organize my thoughts
while((current != NULL) && (akey != current->adata))
{ // indentation inside nested scope
previous = &current->ptr; // no space for unary operators like &
current = current->ptr; // assignments justified to same level
}
if (current != NULL)
{
*previous = current->ptr; // no space for unary *, space for =
delete current;
}
// more blank lines between sections
return;
}
void LinkedListPrint(nodetype *list) // no space for unary *
{ // brackets on their own lines
while (list != NULL) // space around !=
{
cout << "(Node: " << list->adata << ") ";
list = list->ptr; // spaces around <<
}
cout << endl;
}
int main()
{
nodetype *node = new nodetype(5, new nodetype(10, // justified stuff
new nodetype(7, new nodetype(14,
new nodetype(23, NULL)))));
// blank lines
cout << "Build linked list: ";
LinkedListPrint(node);
cout << "Removed node 7: ";
LinkedListDelete(&node, 7);
LinkedListPrint(node);
return 0;
}
I made this code based on the code you provided. It's not quite the same, I changed some things, but it does what you want it to. I had to guess what the structure of nodetype was, and I added a constructor for my convenience. I added some comments pointing out aspects of my style.
Notice that it's easier to read than the code you originally provided. Style is important. People will tell you that you have to use X or Y style, but what really matters is that you pick whatever style you like and stick to it consistently; it will make it easier for you to read and understand your own code quickly.
Believe me you, when you've written a lot of code, you stop being able to remember all of it at once, and being able to figure out what you were doing quickly is essential.
Consider the structure given below,
struct info
{
int data;
struct info *next;
};
if you use the above structure to store records in your linked list, then the following code can be used to delete elements from your linked list,
void delitem()
{
info *curr,*prev;
int tdata;
if(head==NULL)
{
cout<<"\nNo Records to Delete!!!";
}
cout<<"\nEnter the Data to be deleted: ";
cin>>tdata;
prev=curr=head;
while((curr!=NULL)&&(curr->data!=tdata))
{
prev=curr;
curr=curr->next;
}
if(curr==NULL)
{
cout<<"\nRecord not Found!!!";
return;
}
if(curr==head)
{
head=head->next;
cout<<"\nData deleted: "<<tdata;
}
else
{
prev->next=curr->next;
if(curr->next==NULL)
{
temp=prev;
}
cout<<"\nData deleted: "<<tdata;
}
delete(curr);
}
I think it is too simple and easy to delete a node or insert ine in linked-list but it requires precise understanding of its MECHANISM. this example shows how to add and remove nodes however it is not a full program but it reveals the mechanism of adding and deleting and moving alinked-list:
#include <iostream>
using namespace std;
//class Data to store ages. in a real program this class can be any other
//class for example a student class or customer...
class Data
{
public:
Data(int age):itsAge(age){}
~Data(){}
void SetAge(int age){itsAge=age;}
int getAge()const{return itsAge;}
private:
int itsAge;
};
//the most important part of the program is the linked0list
class Node
{
public:
//we just make itsPtrHead when created points to Null even if we pass a pointer to Data that is not NULL
Node(Data* pData): itsPtrData(pData),itsPtrHead(NULL),itsCount(0){}
Data* getPdata()const;
Node* getPnext()const;
int getCount()const{return itsCount;}
void insertNode(Data*);//import bcause it shoes the mechanism of linked-list
void deleteNode(int);//most significant in this program
Data* findData(int&,int);
void print()const;
private:
Data* itsPtrData;
Node* itsPtrHead;
int itsCount;
};
Data* Node::getPdata()const
{
if(itsPtrData)
return itsPtrData;
else
return NULL;
}
Node* Node::getPnext()const
{
return itsPtrHead;
}
void Node::insertNode(Data* pData)
{
Node* pNode=new Node(pData);//create a node
Node* pCurrent=itsPtrHead;//current node which points first to the first node that is the "head bode"
Node* pNext=NULL;//the next node
int NewAge=pData->getAge();//the new age that is past to insertNode function
int NextAge=0;//next age
itsCount++;//incrementing the number of nodes
//first we check wether the head node "itsPtrHead" points NULL or not
//so if it is null then we assign it the new node "pNode" and return from insert function
if(!itsPtrHead)
{
itsPtrHead=pNode;
return;
}
//if the condition above fails (head is not null) then check its value and
//compare it with new age and if the new one is smaller than the head
//make this new one the head and then the original node that head points to it make it its next node to the head
if(itsPtrHead->getPdata()->getAge() > NewAge)
{
pNode->itsPtrHead=itsPtrHead;
itsPtrHead=pNode;
//exit the function
return;
}
//if the condition above fails than we move to the next node and so on
for(;;)
{
//if the next node to the current node is null the we set it with this new node(pNode) and exit
if(!pCurrent->itsPtrHead)
{
pCurrent->itsPtrHead=pNode;
return;
}
//else if it not null(next node to current node)
//then we compare the next node and new node
pNext=pCurrent->itsPtrHead;
NextAge=pNext->getPdata()->getAge();
//if next node's age is greater than new then we want new node
//to be the next node to current node then make the original next to current to be the next to its next
if(NextAge > NewAge)
{
pCurrent->itsPtrHead=pNode;
pNode->itsPtrHead=pNext;
//exitting
return;
}
//if no condition succeeds above then move to next node and continue until last node
pCurrent=pNext;
}
}
// delete a node is a bit different from inserting a node
void Node::deleteNode(int age)
{
//deleting a node is much like adding one the differecne is a bit trickier
Node* pTmp=itsPtrHead;
Node* pCurrent=itsPtrHead;
Node* pNext=NULL;
//1 checking for wether age (node contains age) to be deleted does exist
for(;pTmp;pTmp=pTmp->itsPtrHead)
{
if(pTmp->getPdata()->getAge() == age)
break;
}
//if age to be deleted doesn't exist pop up a message and return
if(!pTmp)
{
cout<<age<<": Can't be found!\n";
return;
}
int NextAge=0;
for(;;)
{
//if age to be deleted is on the head node
if(itsPtrHead->getPdata()->getAge() == age)
{
//store the next to head node
pTmp=itsPtrHead->itsPtrHead;
//delete head node
delete itsPtrHead;
//assign the head new node (node after the original head)
itsPtrHead=pTmp;
//decrement the count of nodes
itsCount--;
//exiting gracefully
return;
}
//moving to next node
pNext=pCurrent->itsPtrHead;
NextAge=pNext->getPdata()->getAge();
//checking next node age with age to be deleted. if they
//match delete the next node
if(NextAge == age)
{
//next node holds the target age so we want its NEXT node
//and store it in pTmp;
pTmp=pNext->itsPtrHead;//Next node of the target node
//pCurrent doesn't yet hold the target age but it is the
//previous node to target node
//change the next node of pCurrent so that it doesn't
//point to the target node but instead to the node right
//after it
pCurrent->itsPtrHead=pTmp;
//delete the target node (holds the target age)
delete pNext;
//decrement number of nodes
itsCount--;
//exit
return;
}
//if pNext doesn't point to target node move to the next node
//by making pCurrent points to the next node in the list
pCurrent=pNext;
}
}
void Node::print()const
{
Node* pTmp=itsPtrHead;
while(pTmp)
{
cout<<"age: "<<pTmp->getPdata()->getAge()<<endl;
pTmp=pTmp->itsPtrHead;
}
}
int main()
{
//note this is not a real proram just we show how things works
Data* pData=new Data(6);
Node theNode(pData);
theNode.print();
pData=new Data(19);
theNode.insertNode(pData);
pData=new Data(20);
theNode.insertNode(pData);
pData=new Data(23);
theNode.insertNode(pData);
pData=new Data(25);
theNode.insertNode(pData);
pData=new Data(30);
theNode.insertNode(pData);
pData=new Data(27);
theNode.insertNode(pData);
pData=new Data(33);
theNode.insertNode(pData);
pData=new Data(18);
theNode.insertNode(pData);
theNode.print();
cout<<endl<<endl;
//int age;
//int index;
//cout<<"Age to finde: ";
//cin>>age;
//cout<<endl;
//theNode.Find(index,age);
//cout<<age<<" : Found on index: "<<index<<endl;
//theNode.modify(age);
//theNode.print();
int age;
cout<<"age to delete: ";
cin>>age;
cout<<endl;
theNode.deleteNode(age);
theNode.print();
cout<<endl<<endl<<endl;
return 0;
}
//modify and other member functions are not the purpose of this program
void Delete()
{
int num;
cout<<"enter node to delete"<<endl;
cin>>num;
node *nodeptr=head;
node *prev;
if(head==0)
{
cout<<"list is empty"<<endl;
}
else if(head->data==num)
{
node *t=head;
head=head->next;
delete t;
}
else
{
nodeptr=head;
prev=head;
while(nodeptr!=NULL)
{
if(nodeptr->data==num)
{
prev->next=nodeptr->next;
node *tem=nodeptr->next;
delete tem;
}
prev=nodeptr;
nodeptr=nodeptr->next;
}
}
}