EDITED:
using c++ to code.
void circularList::deleteNode(int x)
{
node *current;
node *temp;
current = this->start;
while(current->next != this->start)
{
if(current->next->value == x)
{
temp = current->next;
current->next = current->next->next;
delete current->next;
}
else{
current = current->next;
}
}
}
Added the else i'm sorry i kinda forgot to copy that part of the code and yes it is for learning purposes. I'm new to coding with c++ and probably come off as a noob sorry about that.
Also as for this line of code
this->start->value == x
im not sure what you mean by it or where you think it goes, yes there are nodes in the linked list and assume that it will always have at lease 1 node all the time.
Think about this two lines:
current->next = current->next->next;
delete current->next;
Try to determine what you are actually deleting (no its not current->next;, at least not the one you want to delete).
You never move to the next node in your while loop. After your if, you should have:
else
current = current->next;
Also, you might want to consider returning from the function after you've found the node (unless you suspect that two nodes have the same value).
In addition to Justin's and Let_Me-Be's answers, consider what you might need to take care of when
this->start->value == x
If you don't handle that right, you'll lose your whole list (or crash trying to get to it)...
Do you have only a singularly linked list?
Have you considered the STL, perhaps a deque?
Or, if you must have a single linked list then why not take something that it 90% STL (;-) and look at the Boost libraries?
You do seem to be reinventing the wheel here. Why not take some existing - and tested - code and use that?
Is "deleting a node from linked list" the issue or "deleting a node from a circular linked list" the issue?
The difference from non-circular to circular is the line:
while(current->next != this->start)
If the list were non circular it would have been
while(current->next != NULL )
Apart from that, there are issues with the code snippet, which others have already pointed out.
Another thing: Do you check that you have at least one valid node in your list before you call deleteNode?
I ask this as your function does not check for a NULL-value of the start element.
The solution would be to add the line
if(start == NULL) return
as first line of your method to avoid this.
Related
I was reading this: https://www.geeksforgeeks.org/reverse-a-linked-list/
I think I found an easier answer but since it wasn't written their and they used more complicated one I think something is wrong with mine and can't figure it out.
We start from the first node which we will copy and insert it into a new list.
then we go one step to the right, copy the value, create a new list with that value and setting its right the previous list and so on.
What's wrong with my algorithm?
If I interpret your idea correctly, it is something like this:
void forward_list::reverse() {
forward_list new_list;
for(auto& v : *this)
new_list.emplace_front(std::move(v));
std::swap(new_list, *this); // or *this = std::move(new_list);
}
... and this would work. It even looks pretty nice I'd say.
What's wrong with my algorithm?
It's creates a new node for every old node and then has to copy/move the data from the old node to the new node. The old nodes will then be destroyed.
Some types aren't even copyable or moveable so this reverse algorithm couldn't be used with such types.
It invalidates references and iterators.
Consider the alternative, reversing the links. It's a bit more complex but gets the job done without any of the drawbacks mentioned above.
Here's my take on reversing the links, which is not implemented exactly the same way as in the link you shared but it works pretty much in the same way. I think this one has fewer assignments though.
curr will point one step ahead of head and next is used to save the next pointer when the relinking is being done.
void forward_list::reverse() {
if(head) { // must have at least one node
node* curr = head->next; // head + 1
head->next = nullptr; // this will be the new last node
node* next; // for saving next while relinking
while(curr) { // while curr != nullptr
next = curr->next; // save the next pointer
curr->next = head; // relink backwards
head = curr; // move head forward
curr = next; // move curr forward
}
// head now points at the new start of the list automatically
}
}
Your algorithm is functionally correct, but since you are creating an entirely new list instead of reversing the existing nodes in-place, you are using twice the memory. You also have to deal with the cleanup of deleting the old nodes once you have your new list.
I'm having a problem in a function that deletes an element in a singly linked list. The element needs to be deleted conditionnaly with the function ShouldDelete().
I haven't found a similar request in C++ in the forums so any help would be appreciated. It seems that the following code does not work 100% of the time.
void SinglyLinkedList::DeleteObjects(Node *pStartPtr)
{
Node *pPtr = pStartPtr;
Node *temp;
while(pPtr != nullptr)
{
temp = pPtr->next;
if (pPtr->ShouldDelete())
{
delete pPtr;
pPtr = temp;
if(temp != nullptr)
{
pPtr->next = temp->next;
}
}
pPtr = temp;
}
}
Any thoughts ?
Thanks!
As a general C++ advice, I would use std::list instead of a DIY list implementation, but since I wrote quite some list logic myself in the old C-days, I'll give it a go.
There are 2 essential problems with your code.
First of all, whenever removing an element from a single-linked list, you should set the next pointer of the previous element to the next of the deleted one. You can do something like this:
Node *previousNode = …;
while(pPtr != nullptr)
{
Node *nextNode = pPtr->next;
if (pPtr->ShouldDelete())
{
delete pPtr;
previousNode->next = nextNode;
}
else
{
previousNode = pPtr;
}
pPtr = nextNode;
}
Notice that no specific if-tests within the for-loop on nullptr are needed. You should tell the previous node that it now points to the next of the deleted one. If there is no next one, the previous->next will just point to a nullptr, indicating the end of the list.
The second problem is that you don't have any clear 'start of the list'. In my example code above, it becomes quite hard to indicate what the previousNode is. Is it a nullptr? But what if we remove the first element?
You could easily add logic here to indicate keep track of the first element, initialize previousNode to nullptr, and if the first is deleted, just don't set previousNode->next' and keep previousNode equal tonullptr` in that case, but what about the caller? How can the caller know that the first element has been deleted and the list now starts later.
My preferred solution is to have a separate List struct/class, and keep the start of the list (the first Node) as a member in the List struct/class. Instead of passing the startNode to the function, you should pass the List instance.
The code in the while-loop now becomes a bit longer, since you need to adapt previousNode->next=nextNode to this:
if (previousNode)
previousNode->next = nextNode;
else
list->firstNode = nextNode;
If you don't want to introduce a new List struct/class, you could also return the new firstNode as return value from your function, like this:
if (previousNode)
previousNode->next = nextNode;
else
startNode = nextNode;
…
return startNode;
Notice that this second approach only works if the caller if the function is also the one maintaining the list, and there are no other places pointing to the startNode.
In any case, if multithreading is involved, you probably want a decent List class with a kind of mutex (ideally std::list decorated with a mutex).
I am pretty new to pointers, one of my practice problems is to add a node to a linked-list recursively. This code works but I am wondering if this is the correct way to go about this problem.
void addNode(node* head){
if (head->next != NULL)
addNode(head->next);
if (head->next == NULL) {
node* newNode = new node;
newNode->next = NULL;
head->next = newNode;
}
}
I am suspicious about two things in your code.
What the data type node is and whether it includes some data fields that you need to somehow initialize. Currently a default constructor will be called, so all nodes in the linked list, added using your function, will be the same. That may or may not be OK. (Depending on what your prof had in mind. This is a homework question after all).
Another issue that is not quite clear, is that you assume the linked list is always non-empty. If head is null your function will not work. I doubt that this is OK.
I am trying to reverse a linked list using recursion. I made the reverse() function to reverse the list. I created a linked list in main() and also defined print() method.
I don't know what mistake I am making. Please help me correct it. The code snippets are given below.
struct node
{
int data;
struct node *next;
}*head;
void reverse(node **firstnode,node *n)
{
if(n==NULL)
{
head=n;
return;
}
reverse(&head,n->next);
struct node *q=n->next;
n->next=q;
q->next=NULL;
}
void main()
{
......
head=first;
reverse(&first,first);
print(head);
}
It may not address your question directly. However, you mentioned C++11 in the tags. So, take look at std::forward_list. It is a standard container that is based on single linked-list.
List* recur_rlist(List* head)
{
List* result;
if(!(head && head->next))
return head;
result = recur_rlist(head->next);
head->next->next = head;
head->next = NULL;
return result;
}
void printList(List* head)
{
while(head != NULL) {
std::cout<<head->data<<" ";
head = head->next;
}
}
void main()
{
List* list = createNode(2);
append(list, createNode(3));
append(list, createNode(4));
append(list, createNode(5));
append(list, createNode(6));
List* revlist = recur_rlist(list);
printList(revlist);
}
I think you mixed up your addressing at the end of the reverse function, it should probably look like:
q->next=n;
n->next=NULL;
Also, I am not sure if you need the "firstnode" argument.
Since you want to understand the code, and you have several great resources with finished code already, more finished code examples aren't needed. I'll just answer with some concepts and point you at the errors you need to fix.
First, some background concepts.
Linked lists: first and rest
Any linked list is either empty, or can be broken down into first (a node) and rest (a smaller linked list, or empty). This makes recursion much easier.
if (head){
node * first = head;
node * rest = head->next;
}
Invariant (simplified): A guarantee that is always true at the start and end of your function.
In a linked list, you expect that head points to a node, which points to another node, and so forth, until you get to the end, which is signaled by a nullptr. All of the nodes are different. All of the nodes are valid. These are the guarantees that must be true before you call your function and when your function returns.
In a recursive function, the invariants must hold on the sublist you are reversing at every step, because you return from the function at every step. But this makes recursion much easier because all you have to do is make sure that if the input is good, then your function will return a good value at the current step.
End of recursion:
You can prove that your recursive function never gets in an infinite loop by combining the previous concepts. If the invariants hold, then each step will work, and because each recursive call will take rest, which is guaranteed to be either nullptr or a shorter list, eventually we have to reach the end. And of course show that you handle the end.
Okay, on to the actual problems:
You don't handle end of recursion correctly. You just set head=nullptr at the end, and I'm pretty sure that's not what you want for head. You may want to handle the end if (nullptr == n->next), because then you know that is the last node. Of course, you still have to correctly handle the trivial case where nullptr==head.
You don't preserve invariants. You tried, but it looks like your bookkeeping is just all wrong. I suggest using the debugger or 3x5 notecards to step through what you're actually doing to fix the actual work of swapping things around. For example, it looks like you just confused which node is which in this code snippet:
struct node *q=n->next; // n is first, q is rest
// what if nullptr == q?
n->next=q; // n->next = n->next doesn't actually change anything
q->next=NULL; // this must already be true if reverse(rest) did its job
// q and n were swapped?
Also, your function takes "firstnode" but does not use it, but instead sets the global variable "head" as a side effect.
void currentfor()
{
if(current == NULL)
{
cout << "You don't have any members yet!" << endl;
}
else
{
if (current->next == NULL)
cout << "This is the end of the list." << endl;
else
current = current->next;
}
}
void currentbac()
{
if (current == first)
cout << "This is the beginning of the list." << endl;
else
{
list *previous;
previous = first;
while (previous->next != current)
{
previous = previous->next;
}
current = previous;
}
}
I'm ALMOST there but there's still an issue.
How do I know where my current position is when I move my current position? Because whenever I use these two move functions it doesn't seem to be working. I try to add a node at the "current" position when I move but its always adding the item at the end after all the nodes.
PLUS in my previous code I'm not able to change the fact that the "<--current position" is pointing at all the nodes and not at one node.
I want to point to one node so its more clear that user knows that's where the current pointer is.
Hope people understood .-. I'm just not used to C++ but my professor wants me to learn on my own ( whatever that means) I've been trying to get references online its so hard to get linked list info for the project I'm doing.
"I try to add a node at the "current"position when i move but its always adding at the end after all the nodes."
The problem is with you add node code, not your moving code.
You have not posted your add node code, so it is very hard to say what the problem is. You will have to unlink the nodes before and after the new node and link them to the new node, and lso link the new node to the two old ones before and after - always remembering to handle the first and last node carefully. Have you done all that?
If you just need a linked list implementation for your project it's recommended to use std::list. Take a look at http://www.cplusplus.com/reference/stl/list/ . if you wish to learn c++ there is also a tutorial on that page.
If you want to be able to navigate backwards through a linked list, I'd suggest you implement it as a doubly linked list. That is, you have a next and prev pointer on each element. Will be much simpler to navigate that way.
Specify the structure of the node. (I mean the data you are holding in the list node. eg. Int or float or some object). As said by JohnFx best way to traverse backwards is by using a doubly link list. Specify the insertion code you are using and the your node sturture.