Considering that this is my function:
void addtoSameList(const List &another){
for (Node *temp = new Node(*head); temp != nullptr; temp = temp -> next){
Node *ptr = other.head;
Node *temp2 = new Node;
temp2->value = temp->value;
while (ptr -> next != nullptr) {
ptr = ptr -> next;
}
ptr->next = temp2;
temp2->next = nullptr;
}
return;
}
where my goal is to append a linkedlist to itself, I do not know exactly what goes wrong.
If, for example, I have a linkedlist called n in the main function, where I then declare:
n.addtoSameList(n);
meaning that &other is going to be pointing at the same node as n, I figured that I would make a new node and deep copy the contents of n.
However, my two outputs are either that I end up in an infinite loop, or that some node ends up getting skipped.
How do I fix this issue?
This code has numerous issues. First, the interface doesn't suggest that the only use is to append a linked list to itself. Nor does it suggest that a deep copy is necessary in any other case.
So, lets adjust the requirements...
You want a member function that will append a copy of a linked list to the existing one. Then the case of self-appending naturally falls out of the problem description.
The approach here would be to step through the linked list that is passed in, carefully copying each node, then re-adjusting the pointers on the main linked list to point at your new node and the pointer in the new node to be set to appear to be the end of the list. This maintains a list invariant as the list is stepped through.
There is a pitfall here though. If you are self appending, you risk creating an infinite loop. So you should find the end node of the passed in list before you start this process and consistently use it to find out if you've gotten to the end of the list. If you maintain a tail pointer, this is trivial. If you don't, it means a list traversal.
Another way would be to simply create a copy first, carefully maintaining the pointer to the first node of the copy. Then just adjust the tail node's next pointer to point at the new list, and then adjust the tail node (if you maintain that pointer in the LinkedList data structure) to point at the tail node of the copy. And that's probably the way you should go. It's cleaner and more efficient. The main drawback is cleanup when doing exception handling. But, at your level, you shouldn't be concerned with that right now.
Here's an alternate approach. Create three pointers: ptrBegin, ptrEnd and ptrNew. ptrBegin points to the beginning of the linked list and traverse the linked list so that ptrEnd and ptrNew point to the last element of the linked list. Then increment ptrBegin until ptrBegin != ptrEnd at the same time copying the data at ptrBegin to a new node at ptrNew->next and increment ptrNew.
Related
The problem statement is the following:
Given a singly linked list, write a function to swap elements pairwise. For example, if the linked list is 1->2->3->4->5->6->7 then the function should change it to 2->1->4->3->6->5->7, and if the linked list is 1->2->3->4->5->6 then the function should change it to 2->1->4->3->6->5
Here is my solution:
void swapPairs(Node* head) {
if (!head->next || !head)return head;
Node* current = head->next;
Node*prev = head;
while (true) {
Node* next = current->next;
current->next = prev;
if (!next || !next->next) {
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
current = prev->next;
}
}
The issue with the solution is that when it gets to the end of the function, the head no longer points to the beginning of the list since both current and prev have been moved. I've seen other solutions online which do the same thing as I'm doing here, but maybe since they are implemented in C instead of C++, there is some aspect of their code that allows for the head to remain pointing to the start of the list.
I realize that this is probably a really simple issue to solve, but I'm just not currently seeing the solution. What would be the best way to maintain the beginning of the list throughout the algorithm?
The task at hand will be much simpler once you undergo a slight paradigm shift. This might seem more complicated at first, but after pondering it a bit, its simplicity should be obvious.
Simply said: instead of carrying a pointer around -- to the first of each pair of list elements -- as you walk through the list, carry a pointer to the pointer to the first of each pair of list elements. This sounds complicated, on its face value; but once the dust settles, this simplifies the task at hand greatly.
You must have a head pointer stored separately, and you're passing it to swapPairs():
Node *head;
// The list gets populated here, then ...
swapPairs(head);
That's what you're doing now. But rather than doing this, pass a pointer to the head node, instead:
swapPairs(&head);
// ...
void swapPairs(Node **ptr)
{
while ( (*ptr) && (*ptr)->next)
{
// swap the next two elements in the list
// ...
// Now, advance by two elements, after swapping them.
ptr= &(*ptr)->next->next;
}
}
The body of the while loop is going to swap the next two elements in the list, and let's skip over that part for now, and just focus on this bit of logic that iterates through this linked list, a pair of elements at a time. What's going on here?
Well, you are trying to walk through the list, two elements at a time.
Remember, ptr is no longer the pointer to the first element of the pair. It's a pointer to wherever the pointer to the first element of the pair happens to live. So the initial ptr is pointing to your original head pointer.
Once you understand that, the next mental leap is to understand that you want to cycle through your iteration as long as there are at least two elements left in the list:
while ( (*ptr) && (*ptr)->next)
*ptr is the next element to the list, the first of the pair, and (*ptr)->next would therefore be the pointer to the second in the pair. Because of how we're iterating, ptr can be proven, by contract to never be NULL. So, if *ptr is NULL, you reached the end of the list. But if *ptr is not NULL, there's at least one element left, and (*ptr)->next is the "next 2nd element". If (*ptr)->next is NULL, the original list had an odd number of elements in it, so on the last iteration you ended up with *ptr pointing to the odd duck. And you're done in that case too, no need to go any further.
Finally:
ptr= &(*ptr)->next->next;
This simply advances ptr by two elements of the list. Remember, ptr is a pointer to wherever the pointer to the first of the next two elements in the list "happens to live", and this now sets ptr to point the where the pointer to the first of the ***next**** two elements in the list happens to live. Take a piece of paper, draw some diagrams, and figure this out yourself. Do not pass "Go", do not collect $200, until this sinks in.
Once you wrapped your brain around that, the only thing that's left is to swap the pairs. That's it. The body of the loop can simply be:
Node *first=*ptr;
Node *second=first->next;
Node *next=second->next;
*ptr=second;
second->next=first;
first->next=next;
That's it. You're done. And, guess what? Your original head is now automatically pointing to the right head node of the swapped list.
Now, wasn't that easy?
Change the signature of the function to
Node* swapPairs(Node* head)
and save the new head after the first swap, then at the end after your while loop's closing }, return that new head, to replace the old list head held by the caller, which would use this something like:
list = swapPairs(list);
You can keep a pointer to the new head at the beginning of the function and update the head at the end of the function with that. Note that I changed the argument from Node* to Node ** because we want to update the pointer value so that when we update head, we write to the same memory location that passed to this function. As a result, the correct value of head will be available in the caller of this function when we return from it.
void swapPairs(Node **head) {
if (!(*head)->next || !(*head))
return;
Node *new_head = (*head)->next; // the new_head
Node *current = (*head)->next;
Node *prev = (*head);
while (true) {
Node *next = current->next;
current->next = prev;
if (!next || !next->next) {
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
current = prev->next;
}
*head = new_head; // now update the head
}
I feel really silly asking this, as it seems really simple, but I just can't figure it out. All I want to do is set the node pointer to the next node in the list. The function is from a teacher, I wrote the body, so I don't want to mess with the head of the function.
void LList::insert(int num, int at)
{
node* n = new node(num);
if (!n) throw runtime_error("Can't allocate node!");
if(!root || at == 0){
// if empty list - new node is root…
if (!root) root = n;
}
if(root){
node* nextNode = new node(num);
int numF = 0;
for (node* t = root; t != NULL ; t = t->next){
numF++;
if(numF == at){
n->next=t->next;
t->next=n;
}
}
}
}
Since it seems you are using n for the new node to be inserted into the linked list (I'm inferring that it's a singly linked list from the existing code and class name), there are a few things you have to do off the top of my head:
Identify the existing member of the list after which the new node will be inserted. You are making an attempt to do this already with that for loop, but in my opinion you may want to rewrite that as a while loop since you probably don't want it to keep iterating after the insertion position has been identified. Alternately, you could short-circuit out of the for loop with a break once you've found the right place for insertion, but I don't like that for stylistic reasons. :)
Set the newly inserted node's next pointer to the same location to which the next pointer of the node identified in #1.
Set the next pointer of the node identified in #1 to point at the new node, thus re-establishing the integrity of the chain.
Your code looks like it is attempting to do #2 and #3 out of order, which won't work. You're obliterating the value of t->next before you've had a chance to point n->next at it.
Finally, you may need to define some behavior to which you can fall back in case you are adding to a position not already defined in the list (i.e. inserting into the fourth position of a linked list that currently has three elements). You may need to re-jigger your loop to terminate when t->next is null rather than when t itself is null - otherwise you lose the hook to be able to connect the (currently) last element of the list to your new node.
It is difficult to understand how this node is being created, Can you please write step-wise what this set of code is actually doing, and what actions they represent?
void list::create_node(int value)
{
struct node *temp;// Please write in words the meaning of this statement
temp = new(struct node);// is this a dynamic node? )
temp->info = value;// is this value being assigned to this node?
if (last == NULL)// what is this set of code testing??
{
last = temp;// who is this last; the node which has been created?
temp->next = last; // is the node pointing to itself being only one node?
}
else
{
temp->next = last->next;((( // What is this statement saying?
last->next = temp;// What is this statement saying?
last = temp;// What is this statement saying?
}
}
void list::create_node(int value)
{
The above line declares a function that creates a node with the given value and inserts the node into the list. The code must be examined to see where the new node is inserted.
struct node *temp;
Declares a pointer to a node. The memory has not been allocated yet, only a pointer that will be used later.
temp = new(struct node);
Allocates memory for a node from the dynamic (runtime) memory area (a.k.a. heap). Calls the constructor of the node structure to initialize the memory, if a constructor exists.
The pointer temp is now pointing to the node object.
temp->info = value;
This assigns the value to the data field, info. Need the declaration of struct node in order to confirm this guess.
if (last == NULL)
{
Assuming that last is a pointer and points to the last node, this check is looking for an empty list. Common implementation is to have pointer values set to null to mark the end of the list.
last = temp;
temp->next = last;
}
The above code inserts the new node as the last node. The last pointer allows fast access to the end of the list. This allows for reverse iteration without having to traverse all the links to find the last node.
Some implementations set the next field to null to indicate the end of the list, others like this one, make it point to the last node.
else
{
temp->next = last->next;
At this point, the list is not empty.
The new node is made to point to the same node that the last node points to.
This is best understood by drawing the node boxes and arrows pointing to the nodes.
last->next = temp;
Updating the last node to point to itself. See the above section.
last = temp;
Updating the pointer to the last (end of list) node to point to the new node.
}
}
I suggest you draw the linked list and walk through this algorithm a couple of times to see how it works. Also review the singly linked list data type.
The circular reference of the last node may be confusing to you. This may not be the standard implementation that most books describe, but it is valid.
For example, there is an exercise that says:
Write a function to delete a node from a linked list, given only that pointer
And this is the solution:
void deleteNode(Node* toDelete) {
// this function essensially first copies the data from the next pointer
// and then, deletes the next pointer
// However, it doesn't work if trying to delete the last element in the list
Node *temp = toDelete->next; // create a temp, assign to the one after toDelete
toDelete->data = temp->data; // change toDelete's data to the one's after it
toDelete->next = temp->next; // change toDelete's next to the one's after it
delete temp;
temp = nullptr;
}
How can I alter my solution to be able to delete the last element in the linked list, given only the pointer last node?
Obviously you can't; the previous node points to a valid node, and there's no way to change that.
What you could do is add a sentinel node to the end of the list. You would never remove that node, and never use it to store data. Then your solution will work for all data nodes. This doesn't require any changes to the node structure, but does require changes to the way you iterate over the list.
No, it's not possible with a singly-linked list.
The reason is that you need to modify the penultimate node (to make its next pointer null). But there is no way of finding that node from the last node.
In general, you cannot remove a node from a singly-linked list given only a pointer to the node.
What you're currently doing is essentially a "cheat", since you aren't really deleting the node pointed to. You're mutating the list and then deleting the successor of the node pointed to. This makes a difference if some other bit of code somewhere is holding a pointer to that successor when you call this function -- their pointer gets invalidated. So you're removing the data element pointed to, but you aren't removing the node pointed to.
In order to handle deletion of a node in a single linked list like that you would need to modify the node before and after.
+-----+ +----------+ +------+
header----->| |->| toDelete |->| |
+-----+ +----------+ +------+
you would need a pointer to the first element of the list since otherwise it is impossible to do what you want due to the nature of the data structure.
first you find the node before the one you need to delete e.g.
Node* before = header;
for (;before->next != toDelete; before = before->next) {;}
now do before->next = toDelete->next if toDelete is the last node it will be a nullptr otherwise a pointer to the next node
(of course you need to delete what the toDelete points to in both cases)
I've seen a few topics about linked lists, and I've read enough to glean how to do it generally, but I want to make sure I'm not wrongly interpreting the information I've gathered.
Let's say I have:
struct element
{
int val;
element *next;
};
The element *next is a pointer to an element, which will be used to connect the elements together in order to form the linked list.
I've also gathered that you need to have some kind of "tie off" so you don't lose your list. My professor describes it as a trail of balloons, and if you dont have a "tie off" your list can get lost.
So I start off with creating the "tie off" pointer:
element first;
first -> *next = 0; // or null
This is where I get lost... How do I add to the head of a linked list? Ordering it isn't important at this point, I just need to start with an unordered list, I'll get more complicated later.
Something like this?
element addMe;
addMe -> val = 100;
first -> next = *addMe;
Is that right?
What would I do to add something to a non-empty list?
Thanks for the time!
Edit: This is not homework. We have gone over linked lists, and have done an assignment with them. I did not get a very good grade on the assignment, so I am trying to strengthen my understanding before the next assignment. We will use linked lists again.
Edit2: Thanks!
I do not know if this would be considered "homework" or not. I personally do not think it is, considering I will not be using the code I posted here.
With singly-linked lists, the efficient way to add new elements is putting them at the beginning of the list. For your design, this would be:
element newHead;
newHead.next = &list;
You'll notice that newHead is now the first element, and list no longer represents the whole list. This leads to a more functional programming style, where you are creating new lists all the time (see: the cons function in Lisp).
Procedural languages like C++ generally use some wrapper structure like this:
struct list
{
element * first;
void prepend(element * elt)
{
elt->next = first;
first = elt;
}
}
so list prepends are expressed as changing an existing list instead of creating a new one.
With such an auxiliary structure, it is also trival to keep track of the list size, and keep a pointer to the last element for fast appends. These both come at the cost of a few extra instructions for every list operation.
You generally store a pointer to the first node:
element* first = &first_node; // this "ties" it off
first->val = 5; // set first node value to 5
first->next; // pointer to next node
If your list is empty then first should be set to NULL.
Also, the last node in your list should have next be set to NULL.
you got to have a first pointer or head pointer or whatever you may call it. its the pointer that is NULL when your linked list is empty. But when you add first element to the linked list add that elements node address to the hear/first pointer too. and from the 2nd node onwards append the new nodes address to end of the list (node whose next pointer is NULL) or at the star by changing head/first and then adding the current head to new head's next.
I don't know if such theory has helped. Just follow examples or write your own code. and if you encounter errors post it on SO. i guess linked list , queue, stack , etc are available on all c or c++ books.
or search for linked list in SO.
this might do for a start: Simple C++ Linked List
If you want to add to the head of the list
struct element *el = (element *) malloc(sizeof(struct element));
el->val = 100;
el->next = first;
Now el is the first element, and first is the second.
In your example, you where overwriting the first element next element with a new one. You where cutting the list and inserting your new element as the second element. Everything after first is now off the list (which is also a list, but you can't access it, since you overwrote the pointer to this 3rd element).
To add to the end of the list, iterate
struct element *e;
e = first;
while (e->next !=0)
e = e->next;
// here e is the last element. Allocate a new one and point e->next to it. And set this new one next to 0.