views:

193

answers:

6

I've been trying to figure out how to reverse the order of a doubly-linked list, but for some reason, in my function void reverse() runs while loop once and then crashes for some reason. To answer some questions ahead, I'm self-teaching myself with my brothers help. This isn't all of the code, but I have a display() function which prints all nodes chronologically from start_ptr and a switch which activates certain functions like

    case 1 : add_end(); break;
    case 2 : add_begin(); break;
    case 3 : add_index(); break;
    case 4 : del_end(); break;
    case 5 : del_begin(); break;
    case 6 : reverse(); break;

This is the geist of my code:

#include <iostream>
using namespace std;

struct node
{
    char name[20];
    char profession[20];
    int age;
    node *nxt;
    node *prv;
};

node *start_ptr = NULL;

void pswap (node *pa, node *pb)
{
    node temp = *pa;
    *pa = *pb;
    *pb = temp;
    return;
}

void reverse()
{
    if(start_ptr==NULL)
    {
        cout << "Can't do anything" << endl;
    }
    else if(start_ptr->nxt==NULL)
    {
        return;
    }
    else
    {
        node *current = start_ptr;
        node *nextone = start_ptr;
        nextone=nextone->nxt->nxt;
        current=current->nxt;
        start_ptr->prv=start_ptr->nxt;
        start_ptr->nxt=NULL;
        //nextone=nextone->nxt;
        while(nextone->nxt!= NULL)
        {
            pswap(current->nxt, current->prv);
            current=nextone;
            nextone=nextone->nxt;
        }
        start_ptr=nextone;
    }
}
+2  A: 

Try this:

node *ptr = start_ptr;
while (ptr != NULL) {
    node *tmp = ptr->nxt;
    ptr->nxt = ptr->prv;
    ptr->prv = tmp;
    if (tmp == NULL) {
        end_ptr = start_ptr;
        start_ptr = ptr;
    }
    ptr = tmp;
}
Borealid
Best one, though I'm having a brain fart because you didn't end the list with the pointer addressed to NULL
danutenshu
Wow, thanks a lot man, I fixed your code up a bit and it looks so much prettier than all my other attempts. All you had to do was add a qualification when `start_ptr==NULL || start_ptr->nxt==NULL` and make your part of the code the else end. Within that, I made sure at the end code, `end_ptr->nxt=NULL;` Thanks a bunch
danutenshu
I'm not really sure why you need those checks - I think the code I gave will work fine without them. And at the end, end_ptr->nxt will be NULL because at the start, start_ptr->prv was NULL. But you're welcome, at any rate.
Borealid
+1  A: 

You can simplify your reverse() quite a bit. I'd do something like this:

void reverse()
{
    if(start_ptr == NULL)
    {
        cout << "Can't do anything" << endl;
    }
    else
    {
        node *curr = start_ptr;
        while(curr != NULL)
        {
            Node *next = curr->next;
            curr->next = curr->prev;
            curr->prev = next;
            curr = next;
        }
        start_ptr = prev;       
    }
}

Explanation: The basic idea is simply to visit each Node and swap the links to previous and next. When we move curr to the next Node, we need to store the next node so we still have a pointer to it when we set curr.next to prev.

Justin Ardini
I think you missed updating the first node's prev to be the second node.
Borealid
Indeed, and I was off-by-one at the start. Should be better now.
Justin Ardini
+1  A: 

EDIT: My first implementation, which was correct but not perfect. Your implementation is pretty complicated. Can you try this instead:

node * reverse(Node * start_ptr)
{
    Node *curr = start_ptr; 
    Node * prev = null;
    Node * next = null;
    while(curr)
    {
        next = curr->nxt;
        curr->nxt = prev;
    curr->prv = next;
        prev = curr;
        curr = next;
    }
    return start_ptr=prev;
}

Here is my updated solution:

node * reverse()
{
    node *curr = start_ptr; 
    node * prev = NULL;
    node * next = NULL;
    while(curr)
    {
        next = curr->nxt;
        curr->nxt = prev;
        curr->prv = next;
        prev = curr;
        curr = next;
    }
    return start_ptr=prev;
}

The logic was correct. But the issue was that I was accepting in input argument start_ptr. Which means that I was returning the local copy of it. Now it should be working.

bits
Does not work and creates circular linked list
danutenshu
I just can't figure out how I might be doing that.Can anyone confirm if this implementation creates a circular linked list?Thanks...
bits
I tried it and it repeated. (e.g. 2nd, 1st, 2nd, 1st, etc.)
danutenshu
Hi Danutenshu, I have updated my solution. I know your issues is already solved, but I would feel much better if you can please let me know if what I have changed is correct?
bits
A: 

Your pswap function is wrong your should swap the pointer not try to create temporary objects and swap them. Should be like that (there might be other mistake later)

void pswap (node *&pa, node *&pb)
{
    node* temp = pa;
    pa = pb;
    pb = temp;
    return;
}
mb14
That won't actually do anything. You need to pass pointers to pointers or references to pointers so the changes apply to the original objects, not local copies.
SoapBox
you are absolutely right, I didn't look at the signature function. Just fixed the temporary object creation mistake
mb14
A: 

I suggest maintaining a link to the last node.
If not, find the last node. Traverse the list using the "previous" links (or in your case, prv).

There is no need to actually change the links around. Traversing using the prv pointer will automatically visit the nodes in reverse order.

Thomas Matthews
A: 

Look at

valuesnextone=nextone->nxt->nxt;

Here nextone->nxt can be null.

Apart from that, try to use pointers to pointers in the swap function.

Diego Pereyra