diff --git a/ruby/simple-linked-list/README.md b/ruby/simple-linked-list/README.md new file mode 100644 index 0000000..712e6aa --- /dev/null +++ b/ruby/simple-linked-list/README.md @@ -0,0 +1,52 @@ +# Simple Linked List + +Write a simple linked list implementation that uses Elements and a List. + +The linked list is a fundamental data structure in computer science, +often used in the implementation of other data structures. They're +pervasive in functional programming languages, such as Clojure, Erlang, +or Haskell, but far less common in imperative languages such as Ruby or +Python. + +The simplest kind of linked list is a singly linked list. Each element in the +list contains data and a "next" field pointing to the next element in the list +of elements. + +This variant of linked lists is often used to represent sequences or +push-down stacks (also called a LIFO stack; Last In, First Out). + +As a first take, lets create a singly linked list to contain the range (1..10), +and provide functions to reverse a linked list and convert to and from arrays. + +When implementing this in a language with built-in linked lists, +implement your own abstract data type. + +* * * * + +For installation and learning resources, refer to the +[Ruby resources page](http://exercism.io/languages/ruby/resources). + +For running the tests provided, you will need the Minitest gem. Open a +terminal window and run the following command to install minitest: + + gem install minitest + +If you would like color output, you can `require 'minitest/pride'` in +the test file, or note the alternative instruction, below, for running +the test file. + +Run the tests from the exercise directory using the following command: + + ruby simple_linked_list_test.rb + +To include color from the command line: + + ruby -r minitest/pride simple_linked_list_test.rb + + +## Source + +Inspired by 'Data Structures and Algorithms with Object-Oriented Design Patterns in Ruby', singly linked-lists. [http://www.brpreiss.com/books/opus8/html/page96.html#SECTION004300000000000000000](http://www.brpreiss.com/books/opus8/html/page96.html#SECTION004300000000000000000) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/ruby/simple-linked-list/simple_linked_list.rb b/ruby/simple-linked-list/simple_linked_list.rb new file mode 100644 index 0000000..3921449 --- /dev/null +++ b/ruby/simple-linked-list/simple_linked_list.rb @@ -0,0 +1,54 @@ +# Class Element +class Element + attr_accessor :datum, :next + + def initialize(datum) + @datum = datum + @next = nil + end +end + +# Class SimpleLinkedList +class SimpleLinkedList + def initialize(stack = []) + @tail = nil + stack.each do |data| + element = Element.new(data) + push(element) + end + end + + def push(element) + element.next = @tail + @tail = element + self + end + + def pop + popped = @tail + return popped if @tail.nil? + + @tail = popped.next + popped + end + + def to_a + arr = [] + while @tail + element = pop + arr.push(element.datum) + end + arr + end + + def reverse! + new_tail = nil + while @tail + element = pop + element.next = new_tail + new_tail = element + end + @tail = new_tail + self + end +end diff --git a/ruby/simple-linked-list/simple_linked_list_test.rb b/ruby/simple-linked-list/simple_linked_list_test.rb new file mode 100644 index 0000000..ae48b05 --- /dev/null +++ b/ruby/simple-linked-list/simple_linked_list_test.rb @@ -0,0 +1,142 @@ +require 'minitest/autorun' +require_relative 'simple_linked_list' + +class LinkedListTest < Minitest::Test + def test_element + element = Element.new(1) + assert_equal 1, element.datum + end + + def test_element_can_hold_a_different_value + # skip + element = Element.new(10) + assert_equal 10, element.datum + end + + def test_element_next + # skip + element = Element.new(1) + assert_nil element.next + end + + def test_element_next_can_be_assigned_to + # skip + first = Element.new(1) + second = Element.new(2) + first.next = second + assert_equal second, first.next + end + + def test_list_push + # skip + list = SimpleLinkedList.new + element = Element.new(1) + assert_equal list, list.push(element) + end + + def test_list_pop + # skip + list = SimpleLinkedList.new + element = Element.new(1) + list.push(element) + assert_equal element, list.pop + end + + def test_list_pop_empty + # skip + list = SimpleLinkedList.new + assert_nil list.pop + end + + def test_list_pop_is_last_in_first_out + # skip + list = SimpleLinkedList.new + first = Element.new(1) + second = Element.new(2) + list.push(first).push(second) + assert_equal second, list.pop + end + + def test_list_empty_to_array + # skip + list = SimpleLinkedList.new + assert_equal [], list.to_a + end + + def test_list_single_to_array + # skip + list = SimpleLinkedList.new + first = Element.new(1) + list.push(first) + assert_equal [1], list.to_a + end + + def test_list_multiple_to_array + # skip + list = SimpleLinkedList.new + first = Element.new(1) + second = Element.new(2) + third = Element.new(3) + list.push(first).push(second).push(third) + assert_equal [3, 2, 1], list.to_a + end + + def test_list_create_from_array + # skip + array = [1, 2, 3] + list = SimpleLinkedList.new(array) + assert_equal [3, 2, 1], list.to_a + end + + def test_list_created_from_array_still_made_up_of_elements + # skip + array = [1, 2, 3] + list = SimpleLinkedList.new(array) + assert_equal Element, list.pop.class + end + + def test_list_from_array_still_acts_as_lifo + # skip + array = [1, 2, 3] + list = SimpleLinkedList.new(array) + element = list.pop + assert_equal 3, element.datum + end + + def test_list_in_place_reverse! + # skip + first = Element.new(1) + second = Element.new(2) + third = Element.new(3) + list = SimpleLinkedList.new + list.push(first).push(second).push(third) + + assert_equal [1, 2, 3], list.reverse!.to_a + end + + def test_list_in_place_reverse_are_the_same_elements + # skip + first = Element.new(1) + second = Element.new(2) + list = SimpleLinkedList.new + list.push(first).push(second) + + list.reverse! + + assert_equal first, list.pop + assert_equal second, list.pop + end + + def test_list_reverse_empty_list + # skip + list = SimpleLinkedList.new + assert_equal list, list.reverse! + end + + def test_works_for_1_through_10 + # skip + list = SimpleLinkedList.new(1..10) + expected = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] + assert_equal expected, list.to_a + end +end