Friday, August 26, 2011

Reverse a linked list

I got a phone interview with a tech company located in San Francisco Bay Area.

The interviewer questioned me about a linked list. I think that a linked list is basic but still can get really hard to answer in a short time under tremendous pressure.

The question goes:

Reverse any given linked list. For example, if a linked list A->B->C is given, return a new linked list C->B->A as an answer.

The interviewer gave me a hint that a simple loop is easier to program than recursion. After I struggled a lot, I came up with a rather clumsy solution. Probably, the interviewer wasn't very impressed.

I should have studied more about data structures...Well, "don't cry over split milk" though.

So today I have thought about a recursion version of the solution. I implemented it in Ruby. It took me quite a time (about 1 hour) to complete the code shown below. Please take a look if you are interested.

require 'test/unit'

class Node
  attr_accessor :value
  attr_accessor :next

  def initialize(value)
    self.value = value
  end

  def add(node)
    n = self
    until n.next.nil?
      n = n.next
    end  
    n.next = node
  end

  def self.from_array(a)
    return nil if a.nil? || a.size == 0
    list = nil 
    a.each do |value|
      if list.nil?
        list =  Node.new(value)
      else
        list.add(Node.new(value))
      end 
    end
    list
  end

  def to_array
    arr = []
    n = self
    until n.nil?
      arr.push(n.value)
      n = n.next
    end
    arr
  end 
end

# returns [head, tail]
def reverse_linked_list_impl(list)
  if list.next.nil?
    return [list, list]
  end
  head, tail = reverse_linked_list_impl(list.next)
  tail.next = list
  list.next = nil 
  return [head, list]
end

def reverse_linked_list(list)
  head, tail = reverse_linked_list_impl(list)
  return head
end

class TestAlgorithm < Test::Unit::TestCase
  def test_from_array
    list = Node.from_array([1, 2, 3])
    assert_equal(1, list.value)
    assert_equal(2, list.next.value)
    assert_equal(3, list.next.next.value)
  end

  def test_to_array
    list = Node.new(3)
    list.add(Node.new(5))
    list.add(Node.new(7))
    assert_equal([3, 5, 7], list.to_array) 
  end
  
  def test_reverse_linked_list
    arr = [1]    
    assert_equal(arr.reverse, reverse_linked_list(Node.from_array(arr)).to_array)
    arr = [1, 2]   
    assert_equal(arr.reverse, reverse_linked_list(Node.from_array(arr)).to_array)
    arr = [3, 1, 2]   
    assert_equal([2, 1, 3], reverse_linked_list(Node.from_array(arr)).to_array)
    arr = [5, 3, 1, 2]   
    assert_equal([2, 1, 3, 5], reverse_linked_list(Node.from_array(arr)).to_array)
 end

 end

1 comment:

Andrew W. Greene said...

$i = 0

class A
attr_accessor :i, :n

def initialize(n = nil)
@i = $i
$i += 1

@n = n
end
end

# direct
head = A.new(A.new(A.new(A.new(A.new(A.new)))))
p head

# reversed
a, head = head, nil
a.n, head, a = head, a, a.n while a
p head