Printing a linked list in C++ (C++98) - c++

I'm attempting to print the nodes in a linked list (forwards direction).
It's defined as follows:
struct Node {
string val;
Node* next;
Node* prev;
};
struct Stew {
Node* first;
Node* last;
};
Where Stew has two special pointers, one pointing to the first element, and one to the last.
I'm positive that what I attempted is correct, but it's actually not.
void print (const Stew& q, char direction) {
assert (!isEmpty(q));
{
Node* current = new Node;
current = q.first;
cout << current -> val;
while((current -> next) != NULL)
{
current = current -> next;
cout << (current -> val);
}
delete current;
}
I know there's a logic mistake in there, but I can't seem to pinpoint it. Any help would be appreciated.

Why do you do not read answers on your question? I already showed you how to print the list in the direct and reverse order. See here.
Implementing a push function in c++

I think your problem might be that you are treating your current pointer like it is an object. Current is a pointer that simply points to another object in memory. Hence your line Node *current = new Node is meaningless and you are losing that Node in memory. Your problem is probably the last line where you delete current. Current is pointing to the last item in your list and when you call delete you are freeing the memory current points to. Hence you are deleting the last object in your list. You only need to use delete when you are creating an object in memory, and current should not be a new item it should be a pointer to existing memory.

First:
Node* current = new Node;
That is totally unnecessary. You don't want to create a new node from the heap. All you want to do is point current node to the head node:
Node* current = q.first;
Then assuming that current is a valid node, and the next pointer will either point to the next valid node or NULL to denote the end of the list, your while() loop is starting off wrong. It should be something like this:
while(current != NULL)
{
cout << current->val;
current = current->next;
}
And of course, remove the call to "delete" at the end.

Related

Passing a linked list without memory leak in C++

In many occasions, we need to modify a linked list drastically so we will sometimes create another linked list and pass it to the old one. For example,
struct node { //let's say we have a linked list storing integers
int data;
node* next;
};
and suppose we already have a linked list storing integers 1,2,3.
node* head; //suppose we already store 1,2,3 in this linked list
node* new_head ; //suppose we make a temporary linked list storing 4,5,6,7
head = new_head; //modifying the original linked list
My Question
If I delete head (the old linked list) before the assignment then the whole program will crash.
Conversely, if I do not delete it, then there will be a memory leak.
Therefore, I am looking for a way to modify the linked list without memory leak.
My attempt
I tried to make a helper function similar to strcpy to do my work.
void passing_node(node*& head1, node* head2){ //copy head2 and paste to head1
node* ptr1 = head1;
for (node* ptr2 = head; ptr2 != nullptr; ptr2 = ptr2->next)
{
if (ptr1 == nullptr){
ptr1 = new node;
}
ptr1->data = ptr2->data;
ptr1 = ptr1->next;
}
}
// note that we assume that the linked list head2 is always longer than head1.
However, I still got a crash in the program and I cannot think of any other way to modify this. Any help would be appreciated.
Easier way to avoid memory leak is to avoid raw owning pointers.
You might use std::unique_ptr (or rewrite your own version):
struct node {
int data = 0;
std::unique_ptr<node> next;
};
You can move nodes.
You can no longer copy nodes (with possible double free issue).
so deep_copy might look like:
std::unique_ptr<Node> deep_copy(const Node* node)
{
if (node == nullptr) return nullptr;
auto res = std::make_unique<Node>();
res->data = node->data;
res->next = deep_copy(node->next.get());
return res;
}
I would suggest preallocating the linked list so it's easy to delete every node in one call. The nodes would then just reference somewhere inside this preallocated memory. For example:
struct Node
{
int value;
Node* next;
};
struct LinkedList
{
Node* elements;
Node* first;
Node* last;
Node* free_list;
LinkedList(size_t size)
{
first = nullptr;
last = nullptr;
elements = new Node[size]{0};
free_list = elements;
for (size_t i = 0; i < size-1; ++i)
free_list[i].next = &free_list[i+1];
free_list[count-1].next = nullptr;
}
~LinkedList()
{
delete[] elements;
}
void Add(int value)
{
if (free_list == nullptr)
// Reallocate or raise error.
// Take node from free_list and update free_list to
// point to the next node in its list.
// Update last node to the new node.
// Update the first node if it's the first to be added.
}
void Free(Node* node)
{
// Search for the node and update the previous and
// next's pointers.
// Update first or last if the node is either of them.
// Add the node to the last place in the free_list
}
};
From here you'll have many strategies to add or remove nodes. As long as you make sure to only add nodes to the allocated elements array, you'll never have any memory leak. Before adding, you must check if the array have the capacity to add one more node. If it doesn't, you either have to raise an error, or reallocate a new the LinkedList, copy over all values, and delete the old one.
It becomes a bit more complicated when the array becomes fragmented. You can use a 'free list' to keep track of the deleted nodes. Basically, a LinkedList of all nodes that are deleted.
Just take notice that my code is incomplete. The basic approach is to create an allocator of some sort from which you can allocate a bulk, use segments of it, and then delete in bulk.

Is this a effective way to delete entire linked list?

In function given below, I simply delete the head-pointer of the list and set head pointer to nullptr (im setting it nullptr because in my print function,I check for nullptr for head node, and ask user to create list first if head-node is nullptr).
void del_list(stud* &orig_head)
{
cout << "Deleting entire list..." << endl;
delete orig_head;
orig_head = nullptr;
}
I have a question regarding the way I choose to delete the list, since im not clearing each node of list, im simply clear the head pointer, what will happen to all the other nodes? Will this approach create a memory leak ?
Edit:
Im not using OOP to implement linked list,im implementing linked list using struct and couple of functions.
I like to handle this problem recursively:
void deleteNode(Node * head)
{
if(head->pNext != NULL)
{
deleteNode(head->pNext)
}
delete head;
}
If we have a list of 5 items:
head->pNext->pNext->pNext->pNext->NULL;
Then, the function will first get called for head, then for each pNext until the last one. When we reach the last one, it will skip deleting the next one (since it's null) and just delete the last pNext. Then return and delete the list from back to front.
This is assuming that each node's pNext is initialized to NULL. Otherwise, you'll never know when you've reached the end of the linked list.
Your code will cause memory leak. To delete it correctly, traverse the list and while traversing delete each node separately. And finally make head pointer to point to NULL value. You can have a look at the following code.
void deleteList(struct Node** head_ref)
{
struct Node* current = *head_ref;
struct Node* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
//Now make head_ref point to null
*head_ref = NULL;
}

Linked List of sorted names C++

I have a problem with a linked list that I had to create.
The program should take in user input of names and then put them into a linked list. This list should be sorted alphabetically, so when a new node is added it should go to the right position.
My code looks like this for now:
struct node
{
string info;
node *next;
};
class Passenger
{
private:
node* pname;
public:
void insert(string);
Passenger();
};//closes Passenger class
Passenger::Passenger()
{
pname = new node;
pname -> info = "ABC";
pname -> next = NULL;
}
void Passenger::insert(string name)
{
node *temp, *p, *s;
p = pname;
s = pname;
temp = new node;
temp->info = name;
if(p-> info == "ABC") //new pname linked list, put temp at the front
{
p->info = name;
p->next = NULL;
}
//if there is already one in the list
while(s != NULL)
{
cout<<"inside while loop"<<endl;
//if new node goes to left
if(temp->info < s->info)
{
temp->next = p;
pname = temp;
}//closes if
if(temp->info > s->info)
{
if(p->next != NULL)
{
s = s->next;
if(s->next == NULL)
s->next = temp;
}//closes if
}//closes if
p = p->next;
s = s->next;
}//closes while
I really don't know how to change it that it works. I got it done when there was one node in the list and then add a second one. But if there are 2 nodes already there I don't know how to sort a third or fourth node in.
Dave
BTW, representing an empty list with a sentinel node containing "ABC" is ridiculous. What if someone wants to store a list that starts with that? Using a NULL pointer to represent an empty list is a near-universal convention.
Also, the nodes don't have to be a different type. The list class itself can be a node. So an instance of the class is just an instance of the first node, with a pointer to the rest of the list. Or, to better handle empty lists, you can have a container class that keeps pointers to the head (and optionally tail, for fast tail-insertion). Implementation helper-functions can be member functions of the nodes, not the container class, if you like, so you can call them on any sub-list.
When I was learning linked-lists, I often found it helped to draw circles for nodes and arrows for pointers on a piece of paper, like in the data structures textbook. Then you don't have to keep as much up-in-the-air mentally while you think through the process and any special-cases (beginning or end of the list).
You could break the problem down into two parts: the search, and the insert.
Your search function should return a pointer to the node before the insert position. i.e. the last node with a string that compares less than the one you're inserting. Your loop in that function then needs to either look ahead to the next element, or keep a prev pointer. Either way, you need to get back to the node before the one that stops the loop.
Inserting after a node is pretty easy. There's a special case when you need to insert a new head of the list, because there's no node to modify to point to the new current list. But you don't need to care whether the node you're inserting after was the end of the list or not.
You can reduce the amount of special cases by using a "dummy" node pointing to the actual first element. This trick might not work for a comparison-based insert, compared to an InsertNth. My answer on that question breaks things down into find and insert, and is written in a C-like style even though that was a Java code-review question. See the InsertAfter and InsertBefore methods.

Deleting a node in circular linked list

I have a basic linked list problem that I have attempted to solve below. I would appreciate any inputs on my approach, correctness of the algorithm (and even coding style). The problem calls for a function that deletes all occurrences of an int in a circular linked list and returns any node from the list or NULL (when the list is null).
Here's some C++ code that I have so far:
struct Node{
Node* next;
int data;
};
Node* deleteNode(Node* &node, int num){
if(!node){
return NULL;
}
Node* given = node;
Node* del;
while(node->next != given){
if(node->next->data == num){
del = node->next;
node->next = node->next->next;
delete del;
}
node = node->next;
}
//Check if the first node needs to be deleted, with variable node pointing to last element
if(given->data == num){
node->next = given->next;
delete given;
}
return node;
}
The delete node; should be delete del;.
Also, use Node* node as parameter, instead of Node* &node which will prevent non-lvalues from passing in.
p.s. Forgot a semicolon after struct definition? :)
Without following all your logic I can see at a glance this code cannot work.
You are checking for the input list being empty and that's the only case in which your code returns NULL. But what happens if you are passed a list in which all elements must be deleted?
This problem also has a subtlety in it. To check if you completed a circular list you need to compare to the first address to see if you got linked back to the start. However if this element has been deleted then by C++ standard you're not even allowed to use its address in a comparison.
To avoid making two passes over the elements to be deleted one possible trick is to "break the loop" when starting iteration so you can check for NULL instead of checking for the address of the starting node.

Coding a function to copy a linked-list in C++

I need to implement an auxilliary function, named copyList, having one parameter, a pointer to a ListNode. This function needs to return a pointer to the first node of a copy of original linked list. So, in other words, I need to code a function in C++ that takes a header node of a linked list and copies that entire linked list, returning a pointer to the new header node. I need help implementing this function and this is what I have right now.
Listnode *SortedList::copyList(Listnode *L) {
Listnode *current = L; //holds the current node
Listnode *copy = new Listnode;
copy->next = NULL;
//traverses the list
while (current != NULL) {
*(copy->student) = *(current->student);
*(copy->next) = *(current->next);
copy = copy->next;
current = current->next;
}
return copy;
}
Also, this is the Listnode structure I am working with:
struct Listnode {
Student *student;
Listnode *next;
};
Note: another factor I am running into with this function is the idea of returning a pointer to a local variable.
The first question you need to ask yourself is what the copy semantics are. In particular, you're using a Student* as node contents. What does copying node contents mean? Should we copy the pointer so that the two lists will point to (share) the same student instances, or should you perform a deep copy?
struct Listnode {
Student *student; // a pointer? shouldn't this be a `Student` object?
Listnode *next;
};
The next question you should ask yourself is how you will allocate the nodes for the second list. Currently, you only allocate 1 node in the copy.
I think you code should look more like:
Listnode *SortedList::copyList(Listnode *L) {
Listnode *current = L;
// Assume the list contains at least 1 student.
Listnode *copy = new Listnode;
copy->student = new Student(*current->student);
copy->next = NULL;
// Keep track of first element of the copy.
Listnode *const head = copy;
// 1st element already copied.
current = current->next;
while (current != NULL) {
// Allocate the next node and advance `copy` to the element being copied.
copy = copy->next = new Listnode;
// Copy the node contents; don't share references to students.
copy->student = new Student(*current->student);
// No next element (yet).
copy->next = NULL;
// Advance 'current' to the next element
current = current->next;
}
// Return pointer to first (not last) element.
return head;
}
If you prefer sharing student instances between the two lists, you can use
copy->student = current->student;
instead of
copy->student = new Student(*current->student);
This is an excellent question since you've done the bulk of the work yourself, far better than most "please do my homework for me" questions.
A couple of points.
First, what happens if you pass in an empty list? You probably want to catch that up front and just return an empty list to the caller.
Second, you only allocate the first node in the copy list, you need to do one per node in the original list.
Something like (pseudo-code (but C++-like) for homework, sorry):
# Detect empty list early.
if current == NULL:
return NULL;
# Do first node as special case, maintain pointer to last element
# for appending, and start with second original node.
copy = new node()
last = copy
copy->payload = current->payload
current = current->next
# While more nodes to copy.
while current != NULL:
# Create a new node, tracking last.
last->next = new node()
last = last->next
# Transfer payload and advance pointer in original list.
last->payload = current->payload
current = current->next
# Need to terminate new list and return address of its first node
last->next = NULL
return copy
And, while you're correct that you shouldn't return a pointer to a local stack variable, that's not what you're doing. The variable you're returning points to heap-allocated memory, which will survive function exit.
I have been trying to do the same thing. My requirements were:
1. Each node is a very basic and simple class (I moved away from the struct model).
2. I want to create a deep copy, and not just a pointer to the old linked list.
The way that I chose to do this is with the following C++ code:
template <class T>
Node <T> * copy(Node <T> * rhs)
{
Node <T> * current = new Node<T>();
Node <T> * pHead = current;
for (Node <T> * p = rhs; p; p = p->pNext)
{
Node <T> * prev = current;
prev->data = p->data;
if (p->pNext != NULL)
{
Node <T> * next = new Node<T>();
prev->pNext = next;
current = next;
}
else
{
prev->pNext = NULL;
}
}
return pHead;
}
This works well, with no errors. Because the "head" is a special case, there is a need for my implementation of a "current" pointer.
The statement
copy->next = current->next
is wrong. You should do
Create the first node copy here
copy->student = current->student;
copy->next = NULL;
while(current->next!=NULL)
{
Create new node TEMP here
copy->next = TEMP;
TEMP->student = current->student;
TEMP->next = NULL;
copy = TEMP;
}
Since you need a copy of the linked list, you need to create a new node in the loop while traversing through the original list.
Listnode *startCopyNode = copy;
while (current != NULL) {
*(copy->student) = *(current->student);
copy->next = new Listnode;
copy = copy->next;
current = current->next;
}
copy->next = NULL;
return startCopyNode;
Remember to delete the nodes of linked list.
#pat, I guess you will get a seg_fault, because you create memory only once. You need to create memory(basically call 'new') for each and every node. Find out, where you need to use the 'new' keyword, to create memory for all the nodes.
Once you are done with this, you need to link it to the previous node, since its a singly linked list, you need to maintain a pointer to the previous node. If you want to learn and should be able to remember all life, don't see any of the code mentioned above. Try to think the above mentioned factors and try to come up with your own code.
As others have pointed out, you need to call new for each node in the original list to allocate space for a copy, then copy the old node to the new one and update the pointer in the copied node.
another factor I am running into with this function is the idea of returning a pointer to a local variable.
You are not returning a pointer to a local variable; when you called new, you allocated memory on the heap and are returning a pointer to that (which of course means that you need to remember to call delete to free it when you are done with the new list, from outside the function).