I'm trying to find a circle in a linked list, and return the node at the beginning of the circle. For example, if the list was A -> B -> C -> D -> C -- we would return C
Here is my code:
ListNode<T> * findCircle()
{
map<ListNode<T>*, bool> addresses;
ListNode<T>* node = head;
if(addresses.find(node)->second)
cout << " wtf " << endl;
while(node)
{
if((addresses.find(node))->second)
{
return node;
}
else
addresses.insert(pair<ListNode<T>*,bool>(node, 1));
node = node->next;
}
return NULL;
}
I have a few questions:
1) is this the right way to approach the problem
2) am I using the most efficient ways to lookup/insert the keys and values into the table
3) why is it not working? When I check in the map for head, before I've inserted head, it still executes that if statement and prints "wtf". My algorithm is to insert the node as a key with a true value if it is not found in the map, otherwise return the node if the key is already in the map.
I tried doing this with std::set but it gave me trouble, so I switched to map. What baffles me is that the following code works (Code to remove duplicates in a linked list, using a lookup table) using exactly the same methodology.
void removeDuplicates()
{
map<T, bool> listData;
ListNode<T> *node;
ListNode<T> *prev = node;
for(node = head; node; node = node->next)
{
if(listData.find(node->data)->second)
{
prev->next = node->next;
delete node;
}
else
{
listData.insert( pair<T, bool>(node->data, 1));
}
prev = node;
}
}
Is it just a fluke that the second block of code does what it is supposed to, but the first does not?
You need to check if the find operation actually finds the data
auto iterator itr = address.find(node);
if(itr != address.end()){
if(itr->second == true){ cout << "WTF" << endl; }
}
similar for the while loop. As for your approach, I think it has the best runtime possible of O(n). All you can do is lower the constant.
addresses.find(node)->second
currently produces undefined behavior when the find() fails, because you're trying to access the second field of a past-the-end iterator. Instead, use
addresses.find(node) != addresses.end()
Also: is it important to find the exact place where a cycle (that's what it's usually called), or do you just want to see whether a cycle exists or not? If yes latter, then an extremely clever algorithm can solve the problem in linear time and constant space using just two pointers, one of which moves twice as fast as the other :)
Related
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.
So my task is to take prewritten code that generates/populates/prints/ destroys a singly linked list and add functions that count the even number of nodes.
The specified prototypes are
int countEven(node * head)
compute and return the number of nodes that are in the linear linked list
int removeEven(node *& head)
remove all the nodes that contain an even number in the linear linked list and return the number of nodes removed
countEven was not a problem and is functioning correctly, however removeEven seems to work on random numbers
For example, main.cpp looks like so...
#include "list.h"
#include <iostream>
using namespace std;
int main()
{
node * head = NULL;
build(head);
display(head);
//PLEASE PUT YOUR CODE HERE to call the function assigned
cout << "The number of even nodes is " << countEven(head) << ".\n";
cout << "The number of even nodes removed was " << removeEven(head) << ".\n";
display(head);
destroy(head);
return 0;
}
and the function removeEven looks like so...
int removeEven(node *& head)
{
node *current;
node *trailCurrent;
int currentData = 0;
int numberOfItemsRemoved = 0;
current = head;
trailCurrent = NULL;
while(current != NULL)
{
currentData = current->data;
if(currentData % 2 == 0)
{
if (head == NULL)
cout << "Cannot delete from an empty list.\n";
else
{
if (head->data == currentData) //Node is in beginning of list
{
current = head;
head = head->next;
delete current;
numberOfItemsRemoved++;
}
else
{
trailCurrent->next = current->next;
delete current;
numberOfItemsRemoved++;
}
}
}
trailCurrent = current;
current = current->next;
}
return numberOfItemsRemoved;
}
The output is random since the build function seems to make random lists with random numbers but here is a sample
Here is the original list: 2 -> 51 -> 44 -> 46 -> 1 -> 49 -> 2 -> 53 -> 52 -> 2
This list contains 10 numbers of items
The number of even nodes is 6.
The number of even nodes removed was 6.
The resulting list is... 51 -> 31571024-> 1 -> 49 -> 53 -> 31571216
This list contains 6 number of items
The sum of all data is: 63142394
Valgrind is telling me there are invalid read and writes of size 8 which tells me that something is being written or read where it shouldn't. I don't think the case for a head node is the problem as the random number appears AFTER the first in the list, in which case I think the delete function is causing problems. Could anyone point out where I'm going wrong? I checked the other entries on deleting stuff from lists and my solution doesn't seem wrong. Thanks for the tips!
This is an example of a guiding principle that I follow, which is more often right than it is wrong: "when something looks too complicated, it's probably quite buggy".
This shouldn't be very complicated, with the right approach.
And the right approach, believe it or not, is not to try to keep the pointer to the current element being examined, but a pointer to the pointer to the current element, for the reasons that should become obvious:
int removeEven(node *& head)
{
node **currentptr= &head;
int numberOfItemsRemoved = 0;
while (*currentptr)
{
if ( (*currentptr)->data % 2) // Odd
{
currentptr = &(*currentptr)->next;
continue;
}
// Remove a node with an even value
node *p= *currentptr;
*currentptr= p->next;
delete p;
numberOfItemsRemoved++;
}
return numberOfItemsRemoved;
}
Fairly certain this will handle all edge cases. Multiple consecutive nodes to remove, removing the first node in the list, the last, etc...
I'm writing an insert algorithm for an ordered linked list. I've got most of the algorithm completed, but the one while loop condition is throwing me off. I think the rest of it I have correct, but any help with it would be appreciated, thanks!
bool MyLinkedList::Insert(ListNode *newNode)
{
// Assume ListNode is a structure and contains the variable int key;
// Assume the function returns true if it successfully inserts the node
ListNode *back = NULL, *temp = head;
if(head == NULL) // Check for inserting first node into an empty list
{
head = newNode;
return true;
}
else
{ // Search for insert location
while((**???**) && (**???**))
{
back = temp; // Advance to next node
temp = temp -> next;
{
// Check for inserting at head of the list
if(back == NULL)
{
newNode -> next = head; // Insert at head of list
head = newNode;
return true;
}
else // Insert elsewhere in the list
{
newNode -> next = temp;
back -> next = newNode;
return true;
}
}
return false; // Should never get here
}
I am assuming you have the following structure for ListNode (based on your prior comment).
struct ListNode {
int Key;
double dataValue;
ListNode *next;
}
On the assumption that the list is ordered based on the key values, the while loop condition should look like this:
while((temp != NULL) && (temp->Key < newNode->Key))
The rest of the code seems to agree with it.
The second argument would need change if the comparison methodology for ordering the sorted list is different than simple key comparison.
while((**???**) && (**???**))
You need to insert your comparisons here. Whatever kind of data is inside the ListNode, you should have some way of comparing two of them. I suspect you have an overloaded operator if it isn't a primitive type.
Recently I have been asked this question on an interview. All I could do is traverse from 9 to 1 from a linked list starting from 0 to 9. Here is the code:
#include <iostream>
typedef struct node {
int data; // will store information
node *next; // the reference to the next node
};
node *head;
int printList(node *traverse) {
if (traverse->next == NULL) {
return -1;
}
traverse=traverse->next;
printList(traverse);
cout << traverse->data << endl;
return 0;
}
int main() {
node *temp = NULL;
node *begin = NULL;
for (int i = 0; i < 10; i++) {
temp = new node;
temp->data = i;
if (begin == NULL) {
begin = temp;
}
if (head != NULL) {
head->next = temp;
}
head = temp;
head->next = NULL;
}
head = begin;
printList(head);
return 0;
}
1) How can I print 0(the first element) with the printList() recursive function?
2) How can I replace printList() recursive function with while loop?
3) If asked in an interview, does the main() function has proper node initialisation and insertation?
They are four possible ways to achieve this, each of which having its own merits.
Recursion
void print_list(node* traverse)
{
if (traverse == NULL) return;
print_list(traverse->next);
std::cout << traverse->data << std::endl;
}
This is maybe the first answer to come in mind. However, the process stack size is limited, so recursion has a pretty low limit. A big list will provoke a stack overflow. This is not a very good design in C++.
Iteration
void print_list(node *n)
{
using namespace std;
deque<node*> res;
for(;n != NULL; n = n->next) res.push_back(n);
for_each(res.rbegin(), res.rend(), [](node* n){cout << n->data << endl;});
}
Of course, if you want to make it the iterative way, you will need to stack the node pointers yourself (on the process heap) and not delegate this job to the call stack. This method lets you print far bigger lists, and is O(n) in computations. It is, however O(n) in memory usage, but you already have a list which use O(n) memory. So this should not be an issue. However, you may really need to avoid memory consumption. Which brings us to the next idea.
Double iteration
void print_list(node *head)
{
node* last = NULL;
while(last != head)
{
node* current = head;
while(current->next != last)
current = current->next;
std::cout << current->data << std::endl;
last = current;
}
}
This may seem a dumb solution, as it has O(n^2) complexity, but that is computation-complexity. It has O(1) memory complexity and, depending on the actual context and exact problem, it may be the answer you need. But this O(n^2) complexity is a lot to pay. Especially if n is so big you wanted to avoid another O(n) allocation. Which brings us to the last idea.
Hack the container
void print_list(node *head)
{
node* last = NULL;
for(node* next; head != NULL; head = next)
{
next = head->next;
head->next = last;
last = head;
}
for(node* next; last != NULL; last = next)
{
next = last->next;
last->next = head;
head = last;
cout << last->data << endl;
}
}
You first modify the container, then iterate in your new order. On a single-linked list, you can just reverse the links, then reverse-iterate while reversing the links again. The beauty of it is it stays O(n) in computing, and O(1) in memory. The problem is that you invalidate the full container while doing this : your outputing operation does not leave the list constant : this is not exception-safe: if your operation fails in middle of iteration, the list is not valid anymore. This may or may not be an issue depending on the problem.
There's an old trick for traversing the list in reverse with a while loop.
You walk the loop in the forward direction, but as you leave each node, you reverse the link -- i.e., you get its current value (the pointer to the next node), but then set it so it contains a pointer to the previous node. When you reach the end of the list, you now have a singly-linked list that goes the opposite direction -- i.e., following the pointers will take you back to the beginning of the list.
So then you walk back to the beginning, printing each node's value out as you go, and (again) reversing the links so when you're done, the list is as it started, with links going from beginning to end.
Note, however, that this can lead to problems in (for one obvious example) multi-threaded code. The entire traversal of the list from beginning to end and back to the beginning has to be treated as a single, atomic operation -- if two threads try to traverse the list simultaneously, very bad things will happen. Likewise, making this exception-safe can be somewhat challenging as well.
IOW, these are rarely effective solutions to real problems (but the same is generally true of linked lists in general). They are, however, effective ways of showing an interviewer that you can play stupid linked-list tricks.
If your list is [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
1) You want to output the list reversed, your printList should look like this:
int printList(node* traverse)
{
if (!traverse)
return (-1);
printList(traverse->next);
std::cout << traverse->data << std::endl;
return (0);
}
2) It is not really possible with a while loop, unless you do really ugly things like concatenating every node's data to the beginning of the result string that you will print.
3) Your main seems very strange to me. I don't understand why your 'head' variable is global, why not in the main itself?
Last but not least, why don't using std::list?
I was asked a question containing this in the interview. It was intended to traverse the single list from both ends simultaneously. So reversing the single list was not an option. Also, memory space complexity should be O(1). I try to solve with nested loops with O(n^2) time complexity. However, more effective way is to use XOR linked list which was mentioned by #chuckcottrill and #jerry-coffin. Single list can be converted to XOR linked list by applying xor operation to prev and next pointers of node. XOR linked list based on the following property of XOR operation.
a^a^b = b (order of left side is not important)
Let's consider a node in single list and its neighboring nodes:
X: address of prev node , Y: address of next node
While converting to XOR list Y' = X^Y (Y': new value of Y)
While reverse traversing on XOR list Y^(Y') =Y^Y^X=X
So we can attain prev node (X) and do reverse traversal. The following code converts the single list to XOR linked list and does reverse traversal (forward traversal is also possible at the same time):
node* curr = head;
node* prev = NULL;
node* next= curr->next;
while (curr) {
next = curr->next;
// apply xor to prev and next
curr->next = (node*)((uintptr_t)(prev)^(uintptr_t)(next));
// move pointers forward
prev = curr;
curr = next;
}
// prev becomes tail node
// -- Reverse Traversal --
curr = prev ; // curr points to tail
prev = NULL;
node* temp;
while (curr) {
cout << curr->data << " ";
temp = curr;
// apply xor to prev and next
curr = (node*)((uintptr_t)(prev)^(uintptr_t)(curr->next));
prev = temp;
}
Please correct me if I am wrong.
This solution uses an Iterative approach. An extra "previous" pointer is used to maintain the node that will eventually follow the node in the reverse order of the list.
public static Nodes reverse(Nodes head){
Nodes temp;
Nodes previous=null;
while(head!=null)
{
temp=head.next;
head.next=previous;
previous=head;
head=temp;
}
return previous;
}
1) Change
if (traverse->next == NULL)
to
if (traverse == NULL)
2)
while(traverse != NULL) {
// print sth
traverse = traverse->next;
}
3) seems ok to me. Why do you declare head outside of main?
traverse->next = traverse;
A possible solution you could use. Another possibility,
traverse = (traverse->next)- (traverse);
but you must error check for over/underflow.
I'm trying to write a method for my LinkedList class that will sort a linked list of Person objects by their name. My method compiles fine but when I try to sort a list of people, the output is incorrect. It also never stops running. For example, this code
Person *p1 = new Person("K", "B");
Person *p2 = new Person("A", "A");
Person *p3 = new Person("S", "M");
Person *p4 = new Person("B", "M");
LinkedList ll;
ll.insertFront(*p1);
ll.insertFront(*p2);
ll.insertFront(*p3);
LinkedList newList = ll.insertionSort();
newList.print();
cout << endl;
Gives this output
B, K
A, A
Could anyone help me figure out where I went wrong with my algorithm? Thanks!
This is the method I use to sort names by both first and last:
int Person::compareName(Person p)
{
if (lName.compare(p.lName) > 0)
{
return 1;
}
else if (lName.compare(p.lName) == 0)
{
if (fName.compare(p.fName) > 0)
{
return 1;
}
else return -1;
}
else return -1;
}
Insertion Sort Method:
LinkedList LinkedList::insertionSort()
{
//create the new list
LinkedList newList;
newList.front = front;
Node *n;
Node *current = front;
Node *trail = NULL;
for(n=front->link; n!= NULL; n = n->link)//cycle through old chain
{
Node* newNode = n;
//cycle through new, sorted chain to find insertion point
for(current = newList.front; current != NULL; current = current->link)
{
//needs to go in the front
if(current->per.compareName(n->per) < 0)
{
break;
}
else
{
trail = current;
}
}
//if it needs to be added to the front of the chain
if(current == front)
{
newNode->link = newList.front;
newList.front = newNode;
}
//else goes in middle or at the end
else{
newNode->link = current;
trail->link = newNode;
}
return newList;
}
You have current->link in your inner for loop, and in the else to the inner for loop. I assume that you really have current = current->link in the for loop or it does nothing. If so, you'd be skipping every other element.
You also have a language thing- you aren't creating new nodes, you're altering the nodes on your original list. That measn you're changing the list as you walk it, which will corrupt the list as you sort it. Behavior is undefined and dependent on the order in which you add elements.
Even after you have fixed any linked list handling issues (which I haven't looked at), your compareName() function has a flaw - when comparing Person objects that have the same last name it may return from the function without providing a value (in the cases where Name.compare(p.fName) <= 0).
Getting an indeterminate result from the compare function will break pretty much any sort.
Since this is likely homework, I'll leave correcting the problem as an exercise.