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
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.
I'm trying to figure out how to update my tail raw pointer to a new tail after removing a node in my linked list. (is homework)
I've defined the head and tail as
std::unique_ptr<Node> head ;
Node* tail ;
and in my function for removing a node from the back I have the following implementation.
int Deque::remove_back(){
if (empty()) {throw std::runtime_error(std::string("Empty"));};
std::unique_ptr<Node> old;
Node* p = head.get();
int return_value = tail->val;
while (p->next != tail)
{p = p->next)}
old = move(tail);
tail = p;
return return_value;
}
So tail is a raw pointer of type Node.
P is a raw pointer of type Node.
Head is a unique pointer of type Node.
I'm setting p = head.get()
so now p points to the head
p = p->next should be iterating down my nodes.
The problem is that p->next != tail
p->next is a pointer to the next node following whatever p is.
I'm trying to set a pointer to a node to be equal to a raw pointer of type node (tail).
Its telling me I can't do this.
I believe its due to p->next not changing into an owning pointer instead of the observing one I declared it to be.
Errors:
Deque.cpp|68|error: no match for 'operator!=' (operand types are 'std::unique_ptr<Node>' and 'Node*')|
Deque.cpp|69|error: cannot convert 'std::unique_ptr<Node>' to 'Node*' in assignment|
Deque.cpp|71|error: no match for 'operator=' (operand types are 'std::unique_ptr<Node>' and 'std::remove_reference<Node*&>::type {aka Node*}')|
The error messages imply that Node::next is a std::unique_ptr<Node>. You cannot compare/assign a std::unique_ptr directly to a raw pointer. You need to use the std::unique_ptr::get() method instead:
while (p->next.get() != tail) {
p = p->next.get();
}
Also, your loop is not taking into account when the list has only 1 node in it (head == tail). p->next will be nullptr on the second iteration and crash. And since you would be removing the last node in the list, you would need to reset head to nullptr. Either way, when assigning p as the new tail, you need to reset p->next to nullptr so it will no longer be pointing at the old node.
Try this:
int Deque::remove_back(){
if (empty()) {
throw std::runtime_error("Empty");
}
int return_value = tail->val;
if (!head->next) {
head = nullptr; // or: head.reset();
tail = nullptr;
}
else {
Node* p = head.get();
Node *prev = p;
while (p->next->next) {
p = p->next.get();
prev = p;
}
tail = prev;
tail->next = nullptr; // or: tail->next.reset();
}
return return_value;
}
That being said, it can be tricky using std::unique_ptr in a linked-list implementation. If you want automatic destruction of nodes, you could just use raw pointers and wrap the list inside of a class that destroys the nodes when itself is destroyed, and then remove_back() can destroy the node being removed.
The STL already has such classes available: std::list (double linked) and std::forward_list (single linked). You should be using them instead of a manual list implementation.
You function has issue when there is only one element. You need a condition (with code duplicate) or make it little bit more complicated:
int Deque::remove_back(){
if (empty()) {throw std::runtime_error(std::string("Empty"));};
Node *newtail = nullptr;
std::unique_ptr<Node> *curr = &head;
while( curr->get() != tail ) {
newtail = curr->get();
curr = &(*curr)->next;
}
tail = newtail;
std::unique_ptr<Node> tmp = std::move( *curr );
return tmp->val;
}
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.
I was wondering was *& means.
Context:
A function is implemented as follows:
void headInsert( Node*& head, int info )
{
Node* temp = new Node(info);
temp->link = head;
head = temp;
}
WHy not just use Node& ?
Thanks
Node*& means "a reference to a pointer to Node" while Node& means "a reference to Node".
Why not just use Node& ?
Because the headInsert function needs to change what the head is pointing to.
You may want to look at the specific call, where reference pointers reveal their use:
Node* pHead = somewhere;
headInsert(pHead, info);
// pHead does now point to the newly allocated node, generated inside headInser,
// by new Node(info), but NOT to 'somewhere'
Let me comment on your example, maybe that makes it more clear:
void headInsert( Node*& head, int info )
{
Node* temp = new Node(info); // generate a new head, the future head
temp->link = head; // let the former head be a member/child of the new head
head = temp; // 'overwrite' the former head pointer outside of the call by the new head
}
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);
}