Our instructor has shown has several examples of functions that process linked lists (Show All Items, Delete At, Insert As Head, Insert As Tail..)
Now, in those example I noticed that he was using different approaches of traversal.
In some instances he would use
while(head !=0)
{
head=head->link;
}
In other instances he uses to move from node to node.
while(head->link !=0)
{
head=head->link;
}
This is confusing to me. Is there a reason to use one over the other for certain operations ?
The second variant will cause a segfault if head is initially NULL.
Other than that, the first variant will iterate N times (where N is the number of items in the list). The second variant will only iterate N-1 times.
The first variant will leave "head" pointing to a "null" value after traversal. The second variant assumes head must be pointing to a good (non-NULL) head value to start with, and will leave head pointing to an element with a null link. Thus the second variant is useful for finding the final element of the list, and the first variant is useful for counting the number of items in the list.
In the first case, he is covering the case where the list might be initially empty (head = nil). You would normally do any processing internal to the loop before the
head = head->link
line.
In the second case, presumably he knows the list is not initially empty. In this case you would normally do any processing after the
head = head->link
line, although you could, if there was a reason, do some before as well. Of course it is also possible that this is not a conscious decision, since professors are people too ;-)
The second example has two problems actually. Use the first, always.
The first problem is as Oli Charlesworth said, in that it will cause a null pointer dereference (segmentation fault) if the loop is entered with head being NULL.
The second problem is that any code between the top of the loop and the head=head->link; statement will not occur on the last node in the linked list. So if this update statement is at the end of the loop (that's the usual way of doing things), then the last node will be completely bypassed. So if your code was this:
while(head->link !=0)
{
dostufftoNode(head);
head=head->link;
}
Then the dostufftoNode() function would be called for every node EXCEPT the last one.
while(head !=0)
{
head=head->link;
}
This will
check if head is not null
set head to head->link
go to one
this will iterate a total of n times
while(head->link !=0)
{
head=head->link;
}
This will
check if head->link is not null
set head to head->link
go to one
this will iterate a total of n-1 times
Related
I need a swapList(LinkedList& Other) function in charge of basically swapping the values of two lists. Currently, it takes the last element of Other and inputs it into the first element of *this. Then it also moves the last element of Other to the front of its list. Here's what I have so far:
Node *nodePtr = Other.head;
Node *temp = this->head;
while(nodePtr){
temp->value = nodePtr->value;
nodePtr->value = Other.head->value;
Other.head->value = temp->value;
nodePtr = nodePtr->next;
}
}
Now, I know of the copy-swap idiom which I believe means I can just call the swap function in the operator=() overload. I just can't seem to figure out the swap. I've played with it a bunch and this is neither my first, nor my last iteration of the function. Any help is much appreciated. Searches just yield swapping nodes in a single list.
Whenever playing with linked lists (or other linked structures), it is a really good idea to get out some paper and a pencil and draw your list, using boxes for values and arrows for pointers, and then use your eraser and new arrows to perform a swap on the paper.
You have to do it such that you never erase an arrow without first adding a new arrow to the target box/value.
Pay special attention to the possibility that the items being swapped are adjacent to each other!
Once you have that figured out you need to write your code to do the same thing in the same order.
I have a linked-list (actually stack, but implemented using LL), I can't reach the last node. I don't know what I'm doing wrong, I searched all over StackOverflow but they wrote the same code as mine.
I have a head node.
struct stack{
int no;
stack *link;
};
stack *top1 = null;
int main(){
while(top1->next!=NULL){
cout << top1->no << endl;
top1=top1->link;
}
}
// I didn't add the rest of the code, because it's a part of my homework, and our teachers search the internet
And this makes sense, I traverse through my stack, but the last node has a *link pointer as NULL, so this loop stops there, and doesn't make anything about the last node.
How can I fix this? Surprisingly I couldn't reach the element with do-while loop either.
BTW I have 10 elements in stack, I can show them by this loop, and adding extra cout for the last node as:
cout << top1->no;
I have no problem with the elements but I have problems with traversal.
Thanks.
Make it
while (top1 != NULL)
You miss the last entry because of your current check and simply stop the element before your last one.
You pretty much want to check if you reached the NULLpointer. If not, you 'eventually' are within a proper element of yours (or entirely wrong, if you fucked something up before).
Im trying to use the insertion sort method in order to sort nodes from a LinkedList. I've adjusted the code so many times but I can't quite seem to get it, keep getting different types of results none which are sorted.
Heres the code:
Node* sort_list(Node* head)
{
Node* node_ptr = NULL;
for(Node* i = head->next; i->next != NULL; i = i->next){
if (i->key < head->key) {
node_ptr = i;
head = head->next;
}
}
return node_ptr;
}
This is a homework problem so instead of outright writing a code, I will first point out where you went wrong.
In an insertion sort like algorithm, obviously there needs to be some kind of swapping that needs to be done between elements that are out of place (that is need to be inserted). Hence start with thinking about how you can swap two elements of the array. Pay special attention to the cases when one is head or one is tail.
Your implemented code doesn't have any trace of pointer swaps so this is where you are wrong.
Next you must think about the cases when we need to sort. In this case, it is rather simple. If the current element and the next are in sorted order (assuming ascending order, current < next). Then nothing needs to be done but simply make the next one the current.
Then you can obviously infer that violation of this case is when you need to swap the elements. After the swap (with proper attention to where the pointers were and will be after sorting), repeat the process till you hit the null wall.
P.S : This is a possible duplicate of another SO question.
I have been asked recently in a job interview to develop an algorithm that can determine whether a linked list is cyclical. As it's a linked list, we don't know its size. It's a doubly-linked list with each node having 'next' and 'previous' pointers. A node can be connected to any other node or it can be connected to itself.
The only solution that I came up at that time was to pick a node and check it with all the nodes of the linked list. The interviewer obviously didn't like the idea as it is not an optimal solution. What would be a better approach?
What you are looking for is a cycle-finding algorithm. The algorithm Joel refers to is called either the 'tortoise and hare' algorithm or Floyd's cycle finding algorithm. I prefer the second because it sounds like it would make a good D&D spell.
Wikpedia overview of cycle finding algorithms, with sample code
The general solution is to have 2 pointers moving at different rates. They will eventually be equal if some portion of the list is circular. Something along the lines of this:
function boolean hasLoop(Node startNode){
Node slowNode = startNode;
Node fastNode1 = startNode;
Node fastNode2 = startNode;
while (slowNode && fastNode1 = fastNode2.next() && fastNode2 = fastNode1.next()){
if (slowNode == fastNode1 || slowNode == fastNode2)
return true;
slowNode = slowNode.next();
}
return false;
}
Blatantly stolen from here: http://ostermiller.org/find_loop_singly_linked_list.html
Keep a hash of pointer values. Every time you visit a node, hash its pointer and store it. If you ever visit one that already has been stored you know that your list is circular.
This is an O(n) algorithm if your hash table is constant.
Another option is that since the list is doubly linked, you can traverse the list and check if the next pointers previous is always the current node or null and not the head. The idea here is that a loop must either encompass the entire list or look something like this:
- -*- \
\ \
\---
At Node * there are 2 incoming links only one of which can be the previous.
Something like:
bool hasCycle(Node head){
if( head->next == head ) return true;
Node current = head -> next;
while( current != null && current->next != null ) {
if( current == head || current->next->prev != current )
return true;
current = current->next;
}
return false; // since I've reached the end there can't be a cycle.
}
You can handle a general complete circular list like this: Loop through the linked list via the first element until you reach the end of the list or until you get back to the first element.
But if you want to handle the case where a portion of the list is circular then you need to also move ahead your first pointer periodically.
Start with two pointers pointing at the same element. Walk one pointer through the list, following the next pointers. The other walks the list following the previous pointers. If the two pointers meet, then the list is circular. If you find an element with a previous or next pointer set to NULL, then you know the list is not circular.
[Edit the question and subject has been reworded to clarify that we're checking for cycles in a doubly linked list, not checking if a doubly linked list is merely circular, so parts of this post may be irrelevant.]
Its a doubly link list with each node
having 'next' and 'previous' pointers.
Doubly-linked lists are commonly implemented with the head and tail of the list pointing to NULL to indicate where they end.
[Edit] As pointed out, this only checks if the list is circular as a whole, not if it has cycles in it, but that was the wording of the original question.
If the list is circular, tail->next == head and/or head->prev == tail. If you don't have access to both the tail and head node and only have one of those but not both, then it should suffice to simply check if head->prev != NULL or tail->next != NULL.
If this isn't a sufficient answer because we're only given some random node [and looking for cycles anywhere in the list], then all you have to do is take this random node and keep traversing the list until you reach a node that matches (in which case it is circular) or a null pointer (in which case it's not).
However, this is essentially the same thing as the answer you already provided which the interviewer didn't like. I'm quite certain that without some magical hack, there is no way to detect a cycle in a linked list, provided a random node, without a linear complexity algorithm.
[Edit] My mind has switched gears now with the focus on detecting cycles in a list as opposed to determining if a linked list is circular.
If we have a case like:
1<->2<->3<->[2]
The only way I can see that we can detect cycles is to keep track of all the elements we traversed so far and look for any match along the way.
Of course this could be cheap. If we're allowed to modify the list nodes, we could keep a simply traversed flag with each node that we set as we're doing this. If we encounter a node with this flag already set, then we've found a cycle. However, this wouldn't work well for parallelism.
There is a solution proposed here [which I stole from another answer] called "Floyd's Cycle-Finding Algorithm". Let's take a look at it (modified to make it a little easier for me to read).
function boolean hasLoop(Node startNode)
{
Node fastNode2 = startNode;
Node fastNode1 = startNode;
Node slowNode = startNode;
while ( slowNode && (fastNode1 = fastNode2.next()) && (fastNode2 = fastNode1.next()) )
{
if (slowNode == fastNode1 || slowNode == fastNode2)
return true;
slowNode = slowNode.next();
}
return false;
}
It basically involves using 3 iterators instead of 1. We can look at a case like: 1->2->3->4->5->6->[2] case:
First we start at [1] with a fast iterator to [2] and another at [3] or [1, 2, 3]. We stop when the first iterator matches either of the two second iterators.
We proceed with [2, 4, 5] (the first fast iterator traverses the next node of the second fast iterator, and the second fast iterator traverses the next node of the first fast iterator after that). Then [3, 6, 2], and finally [4, 3, 4].
Yay, we've found a match, and have thus determined the list to contain a cycle in 4 iterations.
Assuming that someone says "Here a pointer to a member of a list. Is it a member of a circular list?" then you could examine all reachable members in one direction of the list for pointers to the one node that you were given a pointer to in their pointer which should point away from you. If you decide to go in the next direction then you look for next pointers that are equal to the pointer you were first given. If you choose to go in the prev direction then you look for prev pointers that equal the pointer that you were first given. If you reach a NULL pointer in either direction then you have found the end and know that it is not circular.
You could extend this by going in both directions at the same time and seeing if you bump into yourself, but it gets more complicated and it really doesn't save you anything. Even if you implemented this with 2 threads on a multi-core machine you'd be dealing with shared volatile memory comparisons, which would kill performance.
Alternately, if you can mark each node in the list you could try to determine if there was a cycle by looking for your mark while you searched for the end. If you found your mark in a node you would know that you had been there before. If you found an end before you found one of your marks you would know it wasn't circular. This would not work of another thread were trying to do this at the same time, though, because you would get your marks mixed up, but the other implementation wouldn't work if other threads were reordering the list at the same time as the test.
What you need is Floyd's cycle-finding algorithm. You can also think of finding the the intersection point of the cycle as homework.
Here is a clean approach to test if a linked list has cycles in it (if it's cyclical) based on Floyd's algorithm:
int HasCycle(Node* head)
{
Node *p1 = head;
Node *p2 = head;
while (p1 && p2) {
p1 = p1->next;
p2 = p2->next->next;
if (p1 == p2)
return 1;
}
return 0;
}
The idea is to use two pointers, both starting from head, that advance on different speeds. If they meet each other, that's our clue that there is a cycle in our list, if not, the list is cycle-less.
It is unbelievable how wide can complicated solutions spread.
Here's an absolute minimum required for finding whether a linked list is circular:
bool is_circular(node* head)
{
node* p = head;
while (p != nullptr) {
p = p->next;
if (p == head)
return true;
}
return false;
}
int LinkedList::DoStuff()
{
Node *Current = next_;
while ( Current != NULL )
{
Current = Current->next_;
length_++;
}
// At the last iteration we have reached the end/tail/last node
return length_;
}
there are no more nodes beyond the last. How can i traverse to the tail-end to the front-head?
Unless your linked list is a doubly-linked one, this is difficult to do. Recursion is one way, assuming you don't have lists so big that you'll run out of stack space, something like this (pseudo-code):
DoStuffBackwards (currNode) {
if (currNode != NULL) {
DoStuffBackwards (currNode->next);
// Process currNode here.
}
}
DoStuffBackwards (firstNode);
This works because you keep calling DoStuffBackwards() for the next node until you exhaust the list then, as you roll back up the recursion stack, you process each node.
If you just want to go backwards from last node to current node, than Pax's answer (using recursion) is your best bet, also see my version below. If your current node is not the head of your non-circular-singly-linked-list, and you want to go from current node to head node, it is impossible.
int LinkedList::DoStuff()
{
return DoStuffBackward(next_, 0);
}
int LinkedList::DoStuffBackward(Node* node, int n)
{
if (!node)
{
return n;
}
int len = DoStuffBackward(node->next_, n + 1);
std::cout << "doing stuff for node " << n << std::endl;
return len;
}
This has the smell of homework, so no code, but here's an overview of a solution that doesn't require recursion:
If you want to run through the list backward one option to relink the list to point backwards as you're traversing it to find the end. Then as you re-traverse the list (which visits the nodes in the reverse order from the original list) you repeat the relinking same as before and the list ends up in its original order.
This is simple in concept, but handling the pointers and links correctly (especially at the start and end of the list) can be a bit tricky.
Recursion can work, as can building an auxiliary data structure, such as an array with one entry for each element of the original list. If you want a solution for a single-threaded list without requiring O(n) extra storage, the best bet is to reverse the list in place as Michael suggests. I wrote an example for this, [but I'll leave it out given the concern about homework]. One caution about reversing the list: if there are any other data structures that hold pointers to the original list, and you might be accessing them during your traversal, they won't work if they need to access the list while it's reversed, and this might lead to data corruption if they try to modify the list.
Update: Ok, here's the (C++) routine to reverse a list in place. It hasn't been tested, though. And I'll note that if this is homework, the poster still needs to figure out how to use this routine correctly to get a complete answer.
Node *ReverseList(Node *head) {
// Reverse a single-threaded list in place, return new head
Node *prev=NULL;
Node *cur=head;
while (Node *next=cur->next_) {
cur->next_ = prev;
prev = cur;
cur = next;
}
cur->next_ = prev;
return cur;
}
push the list on a stack and then pop them off.
Is your linked list class doubly-linked or singly-linked? If there is no previous pointer inside each node, you can't traverse backwards.
I also suggest you post more code and take the time to make your question readable.