1

You must print a simply linked list backwards:

  • Without recursion
  • With constant extra memory
  • In linear time
  • Leaving the list intact
  • Added Later Two passes at most
Mike
  • 47,263
  • 29
  • 113
  • 177
flybywire
  • 261,858
  • 191
  • 397
  • 503
  • 3
    there already is this question: http://stackoverflow.com/questions/1116720/how-to-read-a-singly-linked-list-backwards – cube Jul 16 '09 at 07:21
  • What counts as a "pass"? reading each edge once? [as an aside: is this going to be a moving/impossible target?] – p00ya Jul 16 '09 at 07:33

6 Answers6

10

Invert the list, print it forwards, invert again. Each step can be done without violating restrictions except the last one.

EDIT: As cube notes in the comments the second and the third stages can be combined into one pass. This gives two passes – first reverse, then print while reversing again.

Community
  • 1
  • 1
sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • It gets funnier... Why not restrict to just one pass? – sharptooth Jul 16 '09 at 07:25
  • 1
    @andy: To get only two passes print it together with doing the second reversion. @sharptooth: Is that even possible? – cube Jul 16 '09 at 07:29
  • @cube: Perfect idea. That't exactly what is required. – sharptooth Jul 16 '09 at 07:30
  • You're pretty vague about how you actually do any of these steps. I don't believe you can invert a linked list in linear time using only constant memory. You could do it in O(n lg n) time, just not O(n). – Craig Gidney Jul 16 '09 at 09:32
  • 1
    @Strilanc: You need three pointers for those and one pass. Just traverse the list and change pointers direction as you go. – sharptooth Jul 16 '09 at 10:05
3

Building on sharptooth's reply, you can combine the printing and second inversion in the same pass.

Edit: The "list is left intact" from a single-threaded view because the post-condition equals the pre-condition.

Edit 2: Not sure how I got the answer, but I'll take it since I've hit the rep cap for the day. I gave sharptooth a +1 too.

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
1

Here's a C# implementation that holds for all the current rules. It mutates the list during the execution, but the list is restored before returning.

using System;
using System.Diagnostics;

namespace SO1135917.Classes
{
    public class ReverseListPrinter
    {
        public static void Execute(Node firstNode, Action<Node> action)
        {
            Reverse(Reverse(firstNode, null), action);
        }

        private static Node Reverse(Node firstNode, Action<Node> action)
        {
            Node node = firstNode;
            Debug.Assert(node != null);

            Node nextNode = node.Next;
            node.Next = null;
            while (node != null)
            {
                if (action != null)
                    action(node);
                if (nextNode == null)
                    break;
                Node nextNode2 = nextNode.Next;

                nextNode.Next = node;
                node = nextNode;
                nextNode = nextNode2;
            }
            return node;
        }
    }
}

There is one problem, however, and that is that the state of the list is undefined if an exception should occur in the above methods. Probably not impossible to handle though.

A subversion repository of the above code, with unit tests, for Visual Studio 2008 is available here, username and password is both 'guest' without the quotes.

Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825
0

You can first check the length of the list. Then create a print-buffer, which you fill in backwards as you traverse the list once again for the information.

Or

You can create another linked list where you add all the printing data in the front when you traverse the first list, and then print the second list from front to back.

Either way makes only two passes at most. The first idea could be done in one pass if you have a header struct that keeps track of the amount of elements in the list.

Edit: I just realised that these ideas does not use constant memory.

The only way to do this sensibly seems to be Sharptooths reply, but that requires three passes.

Tobias Wärre
  • 793
  • 5
  • 11
0

a function like the following might solver your issue:

void invert_print(PtNo l){
  PtNo ptaux = l;
  PtNo last;
  PtNo before;
  while(ptaux != NULL){
    last = ptaux;
    ptaux = ptaux->next;
  }
  while(ptaux != last){
    printf("%s\n", last->info.title);
    ptaux = l;
    before = last;
    while(ptaux != before){
      last = ptaux;
      ptaux = ptaux->next;
    }
  }
}

you will need a structure like the following:

typedef struct InfoNo{
  char title20];
}InfoNo;

typedef struct aPtNo{
  struct InfoNo info;
  struct aPtNo* nextx;
}*PtNo;
0

Objective-C Link class with reverse method:

Link.h

#import <Foundation/Foundation.h>

@interface Link : NSObject

@property(nonatomic) int value;
@property(nonatomic) Link *next;

- (Link*)reversedList;

@end

Link.m

#import "Link.h"

@implementation Link

- (Link*)reversedList {

    Link* head;

    Link *link = self;
    while (link) {

        // save reference to next link
        Link *next = link.next;

        // "insert" link at the head of the list
        link.next = head;
        head = link;

        // continue processing the rest of the list
        link = next;
    }

    return head;
}

@end
Michael Peterson
  • 10,383
  • 3
  • 54
  • 51