punitpawar has asked for the wisdom of the Perl Monks concerning the following question:

Hello ,
I am trying to write a code to reverse a singly linked list. But I am not being successful at it.
I was able to create a singly linked list and print it out without any issues , but during the reversal , I am sort of stuck.
Here is my code below , please correct me . I am doing some mistake in my reverse logic
use strict; use warnings; use Data::Dumper; ## Singly Linked List my $head = { data => undef, next => undef }; my $curr=$head; for (my $i=1;$i<5;$i++){ $curr->{next} ={ data =>$i, next =>undef }; $curr= $curr->{next}; } $curr->{next} ={ data=>undef, next=>undef }; $curr=$head; while(defined($curr->{next})){ print "$curr->{data} \n"; $curr= $curr->{next}; } $curr=$head; my $forward; my $previous; ## Reversing Singly Linked List while(defined ($curr->{next})){ $forward = $curr->{next}; $curr->{next}=$head; $previous=$head; $curr=$forward; $head=$curr; } $curr->{next}=$previous; $curr=$head; ## printing the reversed List while(defined($curr->{next})){ print "enterd \n"; print "$curr->{data} \n"; $curr= $curr->{next}; }

Replies are listed 'Best First'.
Re: Reversing a singly linked list
by GrandFather (Saint) on Feb 15, 2016 at 00:28 UTC

    Why? In Perl you can use an array to efficiently insert and remove elements from anywhere in a list and trivially reverse it if you wish. In fact the easiest way to handle your problem is to convert between a Perl list and a linked list:

    use strict; use warnings; use Data::Dumper; my $forwardList = buildList(1 .. 4); my $reverseList = buildList(reverse getList($forwardList)); print join (', ', getList($forwardList)), "\n";; print join (', ', getList($reverseList)), "\n";; sub buildList { my @elements = @_; my $head = {data => undef, next => undef}; my $next = $head; for my $element (@elements) { $next->{data} = $element; $next->{next} = {data => undef, next => undef}; $next = $next->{next}; } return $head; } sub getList { my ($head) = @_; my @data; while ($head) { last if !defined $head->{next}; push @data, $head->{data}; $head = $head->{next}; } return @data; }

    Prints:

    1, 2, 3, 4 4, 3, 2, 1
    Premature optimization is the root of all job security
      Slightly shorter code (slow night):
      use strict; use warnings; use Data::Dumper; my $forwardList = buildList(1 .. 4); my $reverseList = buildList(reverse getList($forwardList)); print join (', ', getList($forwardList)), "\n";; print join (', ', getList($reverseList)), "\n";; sub buildList { my ($head, $node); for (@_){ $node = add_node($node,$_); $head ||= $node; } return $head; } sub add_node{ my ($prev, $data) = @_; return $prev->{next} ={data=>$data, next=>undef}; } sub getList { my ($head) = @_; my @data = ($head->{data}); while ( $head = $head->{next}) { push @data, $head->{data}; } return @data; }
      (The last node points to undef .. there is no empty node)

              "Think of how stupid the average person is, and realize half of them are stupider than that." - George Carlin

Re: Reversing a singly linked list
by choroba (Cardinal) on Feb 15, 2016 at 10:06 UTC
    You need to wrap the data from the current element in each step, not the whole element:
    $curr = $head; my $tail; while ($curr) { $tail = { next => $tail, data => $curr->{data}, }; $curr = $curr->{next}; } print Dumper $tail;
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      OK Thanks for the response...
      But would you be knowing why the following is running into infinite loop ?
      what am I doing wrong here
      ## Reversing linked list $curr=$head; while (defined ($curr->{next})) { $curr->{next} = { data =>$curr->{data}, next => $curr }; $curr = $curr->{next}; } print Dumper $curr;
        Because you always effectively assign next => $curr , hence it's always defined.

        Try Data::Dumper to check if your data is what you think it should be.

        Cheers Rolf
        (addicted to the Perl Programming Language and ☆☆☆☆ :)
        Je suis Charlie!

      Thanks for the response. And this was very helpful
      But one question which I have from your code is that , aren't you creating a new list itself ?
      So the original list that was created beginning from the head and all the way down , that still continues to remain unaffected
      So after following your approach by creating new tail nodes each time , I agree that we will get a reversed linked list , but the original linked list will continue to be unaffected
      How can your approach be modified so that there will exist only one direction of linked list at any time , either forward or backwards ?
        You are right. You can either assign the new list to the old one:
        $head = $curr;

        The old nodes will be freed, as there's no reference to the head remaining afterwards. Once the head is gone, the next node can be freed, too, and so on.

        Or, you can use a bit more complicated procedure to invert the list in place:

        $curr = $head; my $tail; while ($curr) { my $next = $curr->{next}; $curr->{next} = $tail; $tail = $curr; $curr = $next; }

        ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,