i am trying to implement a linked list.
List has private variables *head, *tail, count.
I understand the logic in the data structure, but admittedly I am new to C++, so i feel like i may be using the constructor incorrectly.
*head and *tail are list node pointers. list nodes then have pointers to previous and next (doubly linked list).
here is what I tried:
List::List():head(), tail(), count(0) {
head->previous = NULL;
head->next = tail;
tail->previous = head;
tail->next = NULL;
}
my program compiles but crashes when it tries to make a new list with this constructor. any suggestions?
Typically, head and tail will be null pointers for an empty list so dereferncing them like this:
head->previous = NULL;
will be undefined behaviour.
The constructor would simply be:
List::List() : head(0), tail(0), count(0) {}
(or use nullptr for head and tail if your C++ is advanced enough).
If your the type of person who likes dummy nodes at the start and end of your lists, you will need to allocate them before trying to use them:
List::List() : count(0) {
head = new somethingOrOther();
tail = new somethingOrOther();
head->previous = NULL;
head->next = tail;
tail->previous = head;
tail->next = NULL;
}
This trick is often used to greatly simplify list insertions and deletions since you never have to worry about whether you're inserting at the end or deleting at the start.
The downside is that the list traversals and searches for nodes (including for deletion) must start at head->next and finish with tail->previous but that's often simpler than worrying about the earlier issues.
Related
In the programming assignment, I need to clone a linked list (its a copy constructor so not returning anything but cloning). The old linked list will be going through some removing and adding elements but the new cloned linked list should remain untouched. How do I do that? When I remove and add new nodes to the old list, it also does the same for the new linked list. How can I avoid this?
this->head = other.head;
this->head->val = other.head->val;
SNode *curr = other.head->next;
SNode *newCurr = nullptr;
while (curr != nullptr) {
newCurr = curr;
curr = curr->next;
}
}
I have tried the above code, but when I modify the old list, ie, adding and removing nodes, it also adds and removes nodes from the new list. What can I do to avoid the modifications happening on the new list?
Your code is not creating new nodes, so this cannot work. A cloned list should consist of new nodes, so the SNode constructor should be called.
For instance:
this->head = other.head;
This will just make the new list point to the same list: now you have two head pointers pointing to the same head node. And then, by consequence, the following assignment doesn't do anything useful, as it really is assigning a member's own value to itself:
this->head->val = other.head->val;
The loop isn't doing anything useful either, as it is not assigning anything to any member that belongs to the new structure. It only assigns to variables, walking through the original list with two variables, where newCurr follows one step behind curr.
Here is a correction of your snippet:
// Deal with boundary case: empty list
this->head = NULL;
if (other.head == NULL) return; // Nothing more to do.
// Clone the head node
this->head = new SNode(other.head->val);
SNode *curr = other.head->next;
SNode *tail = this->head; // tail is a more descriptive name
while (curr != nullptr) {
tail->next = new SNode(curr->val); // Clone current node and append it
tail = tail->next; // This new node is now the tail
curr = curr->next;
}
This assumes you have an SNode constructor that takes a single argument for the node's value.
I was trying to implement linked list in C++, when this idea struck my mind. With standard node definition as
class node {
public:
int data;
node *next;
};
I created an empty list node *head; then tried this
if(head->next == nullptr)
cout<<"Stores nullptr";
if(! head->next)
cout<<"Returns bool values";
But there is no output, so what is stored inside head->next ?
First of all, you should create some space/allocate memory for the node class in main.
Note that
node *head; is only a declaration not a definition. For further details have a look at What is the difference between a definition and a declaration?.
You allocate space for the object
Initialize its values, to be more elegant define a constructor method
node *head = new node;
head->next = nullptr;
head->data=0;
I would still consider this as a duplicate of Linked lists in C++
If you declare node *head;, head is an uninitialized pointer that contains a random address. Dereferencing it is Undefined Behavior?
You need to a) initialize head: node *head = nullptr;, and b) test for that condition: if (head == nullptr) { head = new node; node->head = nullptr; ...
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 am required to make a linked list which can undergo three operations.
All three of these operations must have O(1) complexity.
The operations in question are:
Add to tail
Remove from head
Return middle node
The node structure being used is as followed:
struct node {
int data;
node* link;
node(int input) {
data = input;
link = NULL;
}
};
For removing the head, I have achieved O(1) by just having the usual reference to the head node
if (head != NULL) {
if (head->link == NULL) {
delete head;
head = NULL;
tail = NULL;
}
else {
node* temp = head;
head = head->link;
delete temp;
}
}
For adding to the tail, I have achieved O(1) by having a reference to the tail node
if(head != NULL) {
tail->link = new node(input);
tail = tail->link;
}
else {
head = new node(input);
tail = head;
}
My issue is with returning the middle node. I know how to do this with traversing the list but that means it will have O(n) complexity. My main thought was if I keep a reference to the current position of the middle node I could track it at all times. This works with the Add to tail function because I can just move the middle node forward accordingly. It doesn't work, however, with removing the head as there is no way I can keep moving the middle reference backwards due to it having to be a singly linked list.
I have been assured that it is possible to do this in O(1) and have been hinted that the reason it can be done is because these are the only three operations that the list will ever undergo and there is therefore a pattern for the middle node to follow.
I can't think of any way this can be done short of keeping a reference to every node from the head to the middle node as a bare minimum but have been told that I do not need to do that to achieve O(1).
Any help will be greatly appreciated.
It doesn't work, however, with removing the head as there is no way I can keep moving the middle reference backwards
Good thing you don't have to move the middle backwards, then! Removing the head can only make the middle go forward.
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);
}