Reverse a LinkedList [duplicate] - c++

This question already has answers here:
Create a reverse LinkedList in C++ from a given LinkedList
(10 answers)
Closed 7 years ago.
I'm trying to reverse a linked list and save it into another new liked list and delete the old one, but I get an error when compiling.. Here's the function..
LinkedList LinkedList::reverse(){
LinkedList L2;
Node * temp=head;
while(temp->next!=NULL){
Node * del=NULL;
L2.addAtFront(temp->data);
del=temp;
temp=temp->next;
delete del;
}
return L2;
}

Use this if (and only if) you no longer need the original linked list!
Instead of using addAtFront which is less cheap (because you need to allocate memory for new nodes and destroy the old ones), you can reuse the nodes and the LinkedList (after all, you were going to delete the original one, and simply set the pointers:
LinkedList LinkedList::reverse(){
Node* na = head;
Node* nb = NULL;
Node* nc = NULL;
if(na == NULL) {
return this;
}
nb = na->next;
na->next = NULL;
while(nb != NULL){
nc = nb->next;
nb->next = na;
na = nb;
nb = nc;
}
tail = head; //if you keep a tail?
head = na;
return this;
}
The method works as follows, you scan over the original list and use three references: na, nb and nc. Who are organized in the order of the original list.
Now you know for sure na and nb are effective in the while loop. You first ensure that you will keep a reference to nb's next by storing it in nc. Next you set the ->next of nb to na (originally na->next was nb), so now it is reversed.
Then you shift in the process: na becomes the old nb, nb the old nc. You keep repeating this until you reach the end of the linked list.
You need to do two additional tasks:
- Set the original head's ->next to null, otherwise you will construct a cycle; and
- Set the tail of the original LinkedList to the head.
If you maintain a tail, you will first need to set it to the head.

Related

swapping 2 nodes in a linked list c++

I'm trying to swap 2 adjacent nodes in a linked list (75 and 9 in this case), and every time I run the code, say with a linked list of 75->9->767->2..., I get the whole list just turning to 75->9->75->9->75->9, etc.. I have to update pointers
Your problem is with the lines
nextPtr->next = tempPtr;
nextPtr = tempPtr;
I'm not sure, but i think you only mean to type
nextPtr = tempPtr;
instead.
I guess you are looking for pairwise swap, use this for the same. Let me know if it went fine.
for 75->9->767->2 it produces 9->75->2->762... If you want something different but similar, you can use it and make changes accordingly.
void swap(struct node **head)
{
if (*head == NULL || (*head)->next == NULL)
return;
struct node *prev = *head;
struct node *cur = (*head)->next;
*head = cur;
while (true)
{
struct node *next = cur->next;
cur->next = prev;
if (next == NULL || next->next == NULL)
{
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
cur = prev->next;
}
}
Hint: If you want to swap nodes H (what you're calling hdList) and N (nextPtr) in a linked list you have to make whatever points to H now point to N. You're not keeping track of whatever points to H at all.
That is, suppose you know that part of your list is
... P -> H -> N -> Q ...
and you want to swap H and N. The state of the list after the swap should be
... P -> N -> H -> Q ...
right? But you can't do this because you don't know what used to point to H (i.e. P) so you can make it point to N.
I think you're going to have to go back to the drawing board on this one.
If you want to swap 2 nodes in linked list, why are you trying to swap the pointers and all? Just swap the data in it with the simple swap logic. let the pointers be as it is. If this is not what you want, tell me in detail what exactly you want it to be.

Return a pointer to a sorted list; linked list in C++

i want this function sortPair to take 2 Node pointers and return a pointer to a list of the 2 elements sorted alphabetically. The code below is what I have so far. If someone could let me know where I went wrong, that would be great.
struct Node{
string val;
Node* next;
};
Node* sortPair (Node* p1, Node* p2){
//Assert that neither pointer is null
assert(p1!=NULL);
assert(p2!=NULL);
Node* head=NULL;
Node* current=NULL;
Node* last = NULL;
current = new Node();
if(p1-> val >p2-> val) //If p1->val comes before p2->val in the alphabet
{
current->val = p1->val;
head = current;
last = current;
current = new Node();
current -> val = p2->val;
last = current;
last ->next = NULL;
}
else
{
current->val = p2->val;
head = current;
last = current;
current = new Node();
current -> val = p1->val;
last = current;
last ->next = NULL;
}
return head;
}
A linked list is just a series of nodes that are linked by each element having a pointer to the next one.
From your code, it seems like you do not want to make a list of the two nodes, but rather insert a node into a list that already exists.
If all you want to do is to make a linked list of the two nodes that are there, then set the one with the lower or higher value, depending on how you sort them, to point at the other one. For example, if you are sorting from smallest to biggest, set the smallest node's next pointer to point to the bigger one and return the pointer of the smallest one.
If you want to add one of the nodes into a list of nodes, then you must loop through the list until you find one that is larger or smaller than the node you want to insert. I recommend using a while loop.
If you want to merge two lists, then you must make a new loop that inserts each element of one list into the other list.
There is no need to make a new node for any of this, just use the ones you have and change the next pointers.
Hope this helps.

Sorting Nodes (Linked-list) C++

I'm trying to sort a linked-list. I have a Node called head and it's pointing to the next node, etc.
But when I try to sort the Nodes by the value they carry, I get the sort working because I see it printing out the stuff in the if-statement, but I'm not getting back the linked-list. Where did I go wrong?
Node* head;
void sortlist(){
Node * runner = head;
Node * runner2;
for(runner = head; runner->next != NULL; runner = runner->next){
for(runner2 = runner->next; runner2->next != NULL; runner2 = runner2->next){
if(runner->freq < runner2->freq){
cout<< runner->freq<< " is LT "<<runner2->freq<< endl;
Node * temp = runner;
runner = runner2;
runner2 = temp;
}
}
}
head = runner;
}
I'm only getting back the first Node.
In order to swap two elements in a linked list, consider what you need to change. For example, to get from
Head -> First -> Second -> (NULL)
to
Head -> Second -> First -> (NULL)
you need to update: Head.next, First.next and Second.next. You don't change any of those things when trying to swap nodes, so it can't possibly do what you expect.
Just swapping the values (ie, swap(runner->freq, runner2->freq)) would be much simpler.
you will stop when runner->next == NULL;, which is supposed to be the last element. And then you set head = runner;, which means the head will always be the last element after this routine. Furthermore, I do not trust this swapping.
It seems you vaguely want to do an insertion sort. If you want to do a simple sorting on linked lists, I suggest you to use selection sort: You create another empty list l2, and each time you remove the minimum element from your first list, and add it as the head of l2. The code for the second list is simple:
void prepend(Node* node, Node** list){
//null checks if you want
node->next = *list;
*list=node->next;
}

Trying to make a single-linked list in C++ that stores values in chronological order instead of storing everything backwards

I've been working for hours trying to get this program to insert values into new nodes or "Player" structures for this program.
The thing is, this takes place inside function main(). My teacher requires me to insert as little code as possible since essentially "everything" is there which allows me to change it.
Here's the original code that stores each new value in the head while putting the older value inside "addNew":
Player * head = NULL;
for(int i=0; i<100; i++)
{
Player * addNew = (Player *)malloc(sizeof(Player));
if(head == NULL)
{
head->len = i;
Player * addNew = (Player *)malloc(sizeof(Player));
head->next = NULL;
}
addNew->next = addNew;
addNew->len = i;
}
Player * p = head;
//do this until 'p' has no address.
for(int i=0; p!=0; i++)
{
printf("%s ", p->str);
p = p->next;
}
Does anyone have any ideas on how to solve this?
IMPORTANT: My teacher would like me to not add any new variables or a tail. Please don't ask.
Update: Here's some older code:
//The head is the last one to hold a value. Therefore it gets pushed to the right.
Player * head = NULL;
Original Algorithm
for(int i=0; i<5; i++)
{
Player * addNew = (Player *)malloc(sizeof(Player));
printf("Insert a string: ");
scanf("%s", addNew->str);
addNew->next = head; //assign head's current address to addNew->next
head = addNew; //assign all of addNew to head
}
Update: Here's a new implementation which doesn't work. I can't really find out where exactly that other for loop should go.
addNew->ID = 1;
addNew->ID += i;
if(head == NULL)
{
head = addNew;
addNew->next = head; //assign head's current address to addNew->next
//head->next = addNew;
}
//head->next = addNew;
addNew->next = head;
//head = addNew; //assign all of addNew to head
printf("%d\n", addNew->ID);
Simple trick: have the list* always point to the last element in the list. And set that last element's next pointer to the start of the list. Now you can always easily find both the start and the end of the list with just one pointer. The start is at list->next. Don't call it tail, just "list".
Right now, you're adding everything to the head of the list. However, you want to add to the tail instead.
You already have a pointer to the head. In addition to that though, you'll also need a pointer to the tail. Can you think of a way to get (and update) it?
You could save a pointer to the tail of the list and instead of saving the next item on each node, save the previous one.
This might not be an option but I thought I'd suggest it anyway. Instead of storing things in a different order, you could leave things stored as they are, but simply change the way you output the values. This would not only be very simple to implement, it would also be a faster during list inserts.

What is the pointer-to-pointer technique for the simpler traversal of linked lists? [duplicate]

This question already has answers here:
An interesting C linked list idiom
(11 answers)
Closed 5 years ago.
Ten years ago, I was shown a technique for traversing a linked list: instead of using a single pointer, you used a double pointer (pointer-to-pointer).
The technique yielded smaller, more elegant code by eliminating the need to check for certain boundary/edge cases.
Does anyone know what this technique actually is?
I think you mean double pointer as in "pointer to a pointer" which is very efficient for inserting at the end of a singly linked list or a tree structure. The idea is that you don't need a special case or a "trailing pointer" to follow your traversal pointer once you find the end (a NULL pointer). Since you can just dereference your pointer to a pointer (it points to the last node's next pointer!) to insert. Something like this:
T **p = &list_start;
while (*p) {
p = &(*p)->next;
}
*p = new T;
instead of something like this:
T *p = list_start;
if (p == NULL) {
list_start = new T;
} else {
while (p->next) {
p = p->next;
}
p->next = new T;
}
NOTE: It is also useful for making efficient removal code for a singly linked list. At any point doing *p = (*p)->next will remove the node you are "looking at" (of course you still need to clean up the node's storage).
By "double-pointer", I think you mean "pointer-to-pointer". This is useful because it allows you to eliminate special cases for either the head or tail pointers. For example, given this list:
struct node {
struct node *next;
int key;
/* ... */
};
struct node *head;
If you want to search for a node and remove it from the list, the single-pointer method would look like:
if (head->key == search_key)
{
removed = head;
head = head->next;
}
else
{
struct node *cur;
for (cur = head; cur->next != NULL; cur = cur->next)
{
if (cur->next->key == search_key)
{
removed = cur->next;
cur->next = cur->next->next;
break;
}
}
}
Whereas the pointer-to-pointer method is much simpler:
struct node **cur;
for (cur = &head; *cur != NULL; cur = &(*cur)->next)
{
if ((*cur)->key == search_key)
{
removed = *cur;
*cur = (*cur)->next;
break;
}
}
I think you mean doubly-linked lists where a node is something like:
struct Node {
(..) data // The data being stored in the node, it can be of any data type
Node *next; // A pointer to the next node; null for last node
Node *prev; // A pointer to the previous node; null for first node
}
I agree with the comments about using the STL containers for handling your list dirty work. However, this being Stack Overflow, we're all here to learn something.
Here's how you would normally insert into a list:
typedef struct _Node {
void * data;
Node * next;
} Node;
Node * insert( Node * root, void * data ) {
Node * list = root;
Node * listSave = root;
while ( list != null ) {
if ( data < list->data ) {
break;
}
listSave = list;
list = list->next;
}
Node * newNode = (Node*)malloc( sizeof(Node) );
newNode->data = data;
/* Insert at the beginning of the list */
if ( listSave == list ) {
newNode->next = list;
list = newNode;
}
/* Insert at the end of the list */
else if ( list == null ) {
listSave->next = newNode;
newNode->next = null;
list = root;
}
/* Insert at the middle of the list */
else {
listSave->next = newNode;
newNode->next = list;
list = root;
}
return list;
}
Notice all the extra checking you have to do depending on whether the insertion occurs at the beginning, end or middle of the list. Contrast this with the double pointer method:
void insert( Node ** proot, void * data ) {
Node ** plist = proot;
while ( *plist != null ) {
if ( data < (*plist)->data ) {
break;
}
plist = &(*plist)->next;
}
Node * newNode = (Node *)malloc( sizeof(Node) );
newNode->data = data;
newNode->next = *plist;
*plist = newNode;
}
As Evan Teran indicated, this works well for singly linked lists, but when it's doubly linked, you end up going through just as many if not more manipulations as the single pointer case. The other draw back is that you're going through two pointer dereferences for each traversal. While the code looks cleaner, it probably doesn't run as quickly as the single pointer code.
You probably mean a doubly-linked list, with one of the pointers going forward and the other going backward. This allows you to get to the next and previous nodes for a given node without having to remember the last one or two nodes encountered (as in a singly-linked list).
But the one thing I discovered which made the code even more elegant was to always have two dummy elements in the list at all times, the first and the last. This gets rid of the edge cases for insertion and deletion since you're always acting on a node in the middle of the list.
For example, an empty list is created:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
Obviously, traversing the list is slightly modified (forward version shown only):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
The insertions are much simpler since you don't have to concern yourself with whether you're inserting at the start or end of the list. To insert before the current point:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
Deletions are also simpler, avoiding the edge cases:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
All very much cleaner code and at the cost of only having to maintain two extra nodes per list, not a great burden in today's huge memory space environments.
Caveat 1: If you're doing embedded programming where space still might matter, this may not be a viable solution (though some embedded environments are also pretty grunty these days).
Caveat 2: If you're using a language that already provides linked list capabilities, it's probably better to do that rather than roll your own (other than for very specific circumstances).