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.
Related
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 );
The below code intends to perform insertion of a single element in a linked list and then print it. Although, I am getting a segmentation fault while printing the value in main function. Could you please help me identify what is wrong with it ?
I have tried to print the value of data in the insert function and it works fine which means the creation of new node and assignment of the value to it is working fine.
#include<iostream>
using namespace std;
struct Node {
int data;
Node* next;
};
//insert a new node
Node* insertNode(int data,Node* head)
{
Node* cNode = head;
if (!head)
{
head = new Node;
head->data = data;
head->next = NULL;
}
else
{
while(cNode->next)
{
cNode = cNode->next;
}
cNode->next = new Node;
cNode->next->data = data;
cNode->next->next = NULL;
}
return head;
}
// print a list
void print(Node* head)
{
/*while(head->next)
{
cout << head->data << " ";
head = head->next;
}*/
cout << "printing data" << endl;
cout << "data : " << head->data;
}
int main()
{
cout << "inside main" << endl;
Node* aNode = NULL;
insertNode(2,aNode);
print(aNode);
return 0;
}
I expect the print function to print the value of data for the single node that I created .
Your head parameter in insertNode function should be a reference (or a pointer to pointer to Node). Beacause in the current form, it is an input parameter, but you need to be in-out parameter. It means that in the current code, your aNode variable is NULL and is always stays NULL.
I recommend this:
void insertNode(int data, Node &head)
Then you create an object in main this way: Node aNode;
It will allow you to update the existing variable directly and you don't need a return value. Also, this way it will be a little bit more C++like, your original code is more like a plain C code.
Or if you want to write it in plain C:
void insertNode(int data, Node **head)
Then you change the call from main: insertNode(2, &aNode);
Sorry for the unclear title, I really don't know how to describe this issue. I'm in my first year of computer science so I really don't know much about C++ yet. However, trying to look up this issue did not help.
The issue:
In the main function, the "printRawData" friend function is called twice. The function is supposed to print each element of the linked list stored by the the class "LinkedList". It works the first time, but the second time I get a segmentation fault. I really have no idea what I'm doing wrong. My T.A. said he thinks that the struct's string variable "element_name" is being corrupted when accessed.
Sorry for the messy code, if I'm not explaining my issue well, or if I'm breaking any kind of stackoverflow etiquette. I appreciate any help I get.
//Note: C++ 11 is needed, due to to_string use
#include <iostream>
#include <string>
using namespace std;
struct Node {
string element_name;
int element_count;
Node* next;
};
class LinkedList{
private:
Node* first;
public:
LinkedList();
~LinkedList();
bool isEmpty();
void AddData(string name, int count);
friend void printRawData(LinkedList l);
};
//where the error occurs
void printRawData(LinkedList l){
Node* n = l.first;
while (n != NULL) { //iterates through the linked list and prints each element
cout << n->element_name << " : " << n->element_count << endl;
n = n->next;
}
}
LinkedList::LinkedList(){
first = NULL;
}
LinkedList::~LinkedList(){
Node* n = first;
while (n != NULL) {
Node* temp = n;
n = temp->next;
delete temp;
}
}
bool LinkedList::isEmpty(){
return first == NULL;
}
void LinkedList::AddData(string name, int count){
Node* newnode = new Node;
newnode->element_name = name;
newnode->element_count = count;
newnode->next = NULL;
Node* n = first;
//if the linked list is empty
if(n == NULL){
first = newnode;
return;
}
//if there's only one element in the linked list,
//if the name of first element comes before the name of new element,
//first element's pointer is to the new element.
//otherwise, the new node becomes the first and points to the previous first
//element.
if (n->next == NULL){
if (n->element_name < newnode->element_name){
n->next = newnode;
return;
} else {
newnode->next = first;
first = newnode;
return;
}
}
//if the first element's name comes after the new element's name,
//have the new element replace the first and point to it.
if (n->element_name > newnode->element_name){
newnode->next = first;
first = newnode;
return;
}
//iterating through linked list until the next element's name comes after
//the one we're inserting, then inserting before it.
while (n->next != NULL) {
if (n->next->element_name > newnode->element_name){
newnode->next = n->next;
n->next = newnode;
return;
}
n = n->next;
}
//since no element name in the linked list comes after the new element,
//the node is put at the back of the linked list
n->next = newnode;
}
main(){
LinkedList stack;
stack.AddData("Fish", 12);
stack.AddData("Dog", 18);
stack.AddData("Cat", 6);
printRawData(stack);
printRawData(stack);
}
The function void printRawData(LinkedList l) passes the parameter by value, so it gets a copy of the LinkedList object.
However, the copy contains a copy of the first pointer, but doesn't copy any of the nodes. So when this copy is destroyed, the LinkedList destructor will delete all the nodes.
And then the original is damaged.
You might want to pass a reference instead of creating a copy.
This is also the reason why the std::list has copy constructors and assignment operators that perform a "deep copy", where the nodes are also copied (not just the list head).
I realize this might be a simple problem but I'm not catching it. My requirement is that I have to "4) Delete the linked list and print the list out again. (making sure its gone from memory)"
So I call the delete function and stepping through it, head should be set to NULL when the function finishes.
/*----------------------------------------------------------------------------
* Function: deleteList
* Purpose: delete a link list
* Arguments: head - a pointer to the first node in the linked list
* Returns: N/A
------------------------------------------------------------------------------*/
void deleteList(node *head)
{
struct node *temp;
// Loop through the list, deleting one node at a time.
while(head != NULL)
{
temp = head->next;
delete(head);
head = temp;
}
}
So when I call the print function and send in head, it should be NULL and catch on the first if statement and return to main. But it is bombing out instead.
/*----------------------------------------------------------------------------
* Function: printList
* Purpose: prints a link list
* Arguments: head - a pointer to the first node in the linked list
* Returns: N/A
------------------------------------------------------------------------------*/
void printList(node *head)
{
if (head == NULL)
{
cout << "Empty List!\n";
return;
}
struct node *temp;
temp = head;
// Loop through the list, printing one node at a time.
while(temp->next != NULL)
{
cout << temp->next->element << endl;
temp = temp->next;
}
}
Now if I use the following in main it works fine. But I'd like to know what small thing im missing in the print function. Been banging my head on this for a while now so I'd thought I would step back and ask for a little guidance.
int main()
{
....
cout << "\n***************** DELETE LIST & PRINT ********************\n";
deleteList(head);
cout << head->element << endl; // This works and shows the list is empty.
//printList(head); // This bombs the program.
....
}
Thanks much.
Node is defined below:
struct node
{
string element;
struct node *next;
};
Declaring head in main:
struct node *head;
//creating head node.
if ((head=new(node)) == NULL)
{
cout << "Error: Could not create head node.\n";
return 1;
}
head->next = NULL;
When you use in main
deleteList(head);
A copy of the pointer "head", pointing to the same place, is passed as parameter.
So, if you change the variable that "head" points to, e.g.:
delete(head);
this will be visible in main(). But when you update the pointer "head" itself, e.g.:
head = temp;
The only pointer updated is the one in the scope of the function, and not the one in main. So now your "head" pointer in main points to a deleted variable.
To solve the issue, you could return the new place that "head" should point to, like so:
node *deleteList(node *head)
{
struct node *temp;
// Loop through the list, deleting one node at a time.
while(head != NULL)
{
temp = head->next;
delete(head);
head = temp;
}
return head;
}
And call it with
head = deleteList(head);
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);
}