My mind is confused at the moment:
struct Node {
int data;
struct Node *next;
}
void Print(Node *head) {
}
This is a code snippet from HackerRank. While this is easy, I just started wondering something: If I modify the head in the Print function, does it modify the original head in the main as well, or is it just the local variable head that is modified?
You passed in a pointer by value, if you modify that pointer then it will not affect the original.
However if you modify what is pointed to by that pointer then it will affect the original.
For instance head = nullptr; would not, while head->data = 1; would.
Also note that any recursion you do will similarly change the original data, for instance an algorithm to add to the end of the list:
Node* previous = head
Node* current = head->next;
while (current != nullptr)
{
previous = current;
current = previous->next;
}
previous->next = new Node(); //However you create one.
Since it uses head->next and eventually modifies the result it will modify the original list.
Related
I am trying to implement a stack using a Linked List. My program keeps crashing and when trying to print the new Linked List, it prints an unsigned integer. My print function works fine, so it is this function below.
Please help.
void LinkedList::Push (int val)
{
Node* newHead = new Node;
Node* oldHead = new Node;
newHead->value = val;
oldHead = head;
head = newHead;
oldHead->prev = head;
head->next = oldHead;
delete newHead;
}
One issue is that the Node that you've newed in the definition of oldHead is never deleted. Since you set oldHead to head immediately after creating it, I would suggest this as your definition:
Node* oldHead = head;
The main issue, though, is that you delete newHead, which is now what head points to. Therefore, when you go to print head, you are reading invalid data.
I would highly recommend leaving the resource handling to objects like std::shared_ptr instead of newing and deleteing yourself.
I'm not sure I understood your question.
Your fixed method:
void Push( const int val )
{
Node* newNode { new Node };
newNode->value = val;
newNode->next = head;
head = newNode;
}
Read more about Linked List operations here. You do not need a doubly linked list to implement a stack - you only need to push/pop at one end.
[EDIT]
I didn't notice you are using a doubly linked list (this is why a complete/verifiable example is required). As I said, for a stack implementation, a singly linked list is enough.
The below is meant to reverse a linked list. It seems to work till it gets to the last line. When I debug, both "current" and "result" are of the same type (Node*) and "result" is the list reversed. But when the function completes, current only has the first value of the "result" list. Anyone know why "current" is not the full list when the function completes?
struct Node {
int data;
Node* next;
};
void reverseList(Node** head)
{
Node* current = *head;
Node* result = NULL;
while (current != NULL)
{
Node* temp = current;
current = temp->next;
temp->next = result;
result = temp;
}
current = result;
}
There are multiple problems with the shown logic.
We can start with the obvious observation that the goal of reverseList is, apparently, to reverse a singly-linked list.
The second observation is that the function takes a single parameter, a pointer to the head node, and it returns a void.
From, that we conclude that the function should update the head node, but there's nothing in the code that does that.
Additionally, there's really no reason why this function should take a double pointer like that, a pointer to the head node, and update it. It's much simpler for the function to take an ordinary pointer to the first element of the list, the existing head pointer, and then return the head pointer of the reversed list.
With this simple change, the resulting logic becomes much, much shorter and simpler:
Node *reverseList(Node *head)
{
Node *current=NULL;
while (head)
{
Node *next=head->next;
head->next=current;
current=head;
head=next;
}
return current;
}
That's it.
you need to update the head at the end of your algorithm:
current = result;
*head = current;
I have a queue add function implemented
void queue::add(myObj info)
{
node* node = new node;
node->info = &info; //<---suspect
node->next = NULL;
if(head == NULL){
head = node;
}
else{
tail->next = node;
}
tail = node;
count++;
}
Every time this gets visited the head node's data points to whatever I'm passing in. I realize there is a template for this but I am trying to build one, because I obviously need practice.
I am trying to keep all the pointers pointed to the original objects. I wanted to pass in the object and point to the refrence.
The node is a struct with myObj * info and node * next
info is a parameter of your function, that is passed by value. In this case, &info is the address of the parameter, and not of the original data.
This is undefined behaviour and can only give weird results.
One possible solution would be:
void queue::add(myObj& info) // pass by reference
{
... // unchanged code
}
In this case, &info would refer to the address of the original object.
Could someone please tell me why are pointers head and tail different when exiting function reverse?
struct elem{
int val;
elem* prev;
elem* next;
...
};
void print(elem* head,elem* tail){...}
void insertAtEnd(elem* e,elem* tail){...}
void reverse(elem* head,elem* tail){
elem* headref = head;
elem* temp = head;
while(temp != NULL){
elem* t = temp->prev;
temp->prev = temp->next;
temp->next = t;
temp = temp->prev;
}
head = tail;
tail = headref;
print(head,tail);
}
int main(){
elem* head = new elem();
elem* tail = new elem();
...
print(head,tail);
reverse(head,tail);
print(head,tail);
return 0;
}
print() inside function reverse works fine. Next print (just before return 0 in main) causes segmentation fault (head->next points to NULL).
With void reverse(elem* head,elem* tail), you don't modify pointer (you may modify content).
You probably mean
void reverse(elem*& head, elem*& tail)
to modify head and tail.
Calling reverse doesn't change head and tail because they are passed by value (reverse only modifies its private copies). If you change the declaration of reverse to
void reverse(elem *&head, elem *&tail)
It should work.
The pointers in main() themselves don't change after calling reverse(), because you pass them to reverse() by value, and the code in the function only modifies its own copies of the pointers. However, the contents of the elem objects they point to have been changed by the reverse() function.
That is, head in main() still points to the same elem object it used to point to before, but now that elem object is the tail of the list (because you changed its contents in the reverse() function and now its next member is nullptr). Similarly, tail in main() points to an elem that is now the head of the list.
Without analysing your code in detail, When you are reversing you are passing pointers to your elements, so the one called head is now the tail and the one called tail is now the head.
So after you will need to print( tail, head )
Your print function obviously does not check for null that is, it will cause an access violation if next is nullptr before it reaches your tail. And it will be because head is the tail so its next will indeed be nullptr.
If you actually want the reverse function to change the pointers themselves as well as what they point to, so you get a reversed list with the names head and tail swapped, pass them by reference.
Your exchange of pointers inside reverse() is local. It will be discarded once you leave the function scope. To achieve the exchange, yo0u have to use double pointers:
void reverse(elem** head, elem** tail){
elem* headref = *head;
elem* temp = *head;
while(temp != NULL){
elem* t = temp->prev;
temp->prev = temp->next;
temp->next = t;
temp = temp->prev;
}
*head = *tail;
*tail = headref;
print(*head,*tail);
}
And pass addresses of head and tail:
reverse(&head, &tail);
P.S. Sorry for possible bugs - I didn't test the code
I'm working on a project and I was given this function to complete
void addToEnd(node*& head, string newVal)
Effect: adds new node to tail end of list
Precondition: head is a pointer to first node in the list (list MAY be empty)
Postcondition: list contains one more node
My question is what is the string newVal for?
The value_type of this class is of type DOUBLE so I'm confused what string newVal is for. So I can't set the newVal in the node because it is of two different types.
This is what I have so far. I'm not sure if im going in the right direction.
node *temp = new node;
temp = head;
while(temp->link() != NULL){
temp = temp->link();
}
head->set_link(temp);
I'm not even sure where to use the string in this block of code.
link() returns the member variable node* link_field
set_link() sets the new link to the link_field
Well, we're guessing that they somehow expect you to turn a string into a double with a function like std::stod.
As for your list manipulation code, there's a few problems:
node *temp = new node;
temp = head;
This creates a new node, puts its pointer in temp, then immediately overwrites temp with head, losing (leaking) the new node. Don't do that.
while(temp->link() != NULL){
temp = temp->link();
}
This is close, but might not work. The problem is that you need to keep track of the real node pointer, not a copy.
Normally, in a linked list API using pointers instead of references, the "add node" function looks like:
void addToEnd(node** head, string newVal)
{
while(*head)
head = &((*head)->next);
*head = new node;
(*head)->value = newVal;
(*head)->next = 0;
}
Note that if the list is empty, the passed-in head pointer is altered to point to the new node. If the list is not empty, the last next pointer is altered instead.
The API you're given (i.e. the link and set_link methods) doesn't allow this, because the head pointer is not a node and those functions require a node. So you've got to do it a little differently, namely you have to handle the empty list case separately.
void addToEnd(node*& head, string newVal)
{
// Create the node.
node* newNode = new node;
newNode->value = std::stod(newVal);
newNode->set_link(0);
if(!head) // Empty list?
{
head = newNode;
return;
}
// Find last node.
node* item = head;
while(item->link())
item = item->link();
item->set_link(newNode);
}