diff --git a/lib/linked_list.rb b/lib/linked_list.rb index 136d8ac9..3f4aa590 100644 --- a/lib/linked_list.rb +++ b/lib/linked_list.rb @@ -2,7 +2,7 @@ class Node attr_reader :data # allow external entities to read value but not write attr_accessor :next, :previous # allow external entities to read or write next node - + def initialize(value, next_node = nil, previous_node = nil) @data = value @next = next_node @@ -12,331 +12,332 @@ def initialize(value, next_node = nil, previous_node = nil) # Defines the singly linked list class LinkedList - def initialize - @head = nil # keep the head private. Not accessible outside this class - @tail = nil - end - - # method to add a new node with the specific data value in the linked list - # insert the new node at the beginning of the linked list - # Time Complexity: O(1) - # Space Complexity O(1) - def add_first(value) - new_node = Node.new(value) - new_node.next = @head - - @head.previous = new_node unless @head.nil? - @head = new_node - if @tail.nil? - @tail = @head - end + def initialize + @head = nil # keep the head private. Not accessible outside this class + @tail = nil + end + + # method to add a new node with the specific data value in the linked list + # insert the new node at the beginning of the linked list + # Time Complexity: O(1) + # Space Complexity O(1) + def add_first(value) + new_node = Node.new(value) + new_node.next = @head + if !@head.nil? + @head.previous = new_node end - - def remove_first() - raise ArgumentError, "Empty" if self.empty? - - value = @head.data - @head = @head.next - @head.previous = nil - return value + @head = new_node + if @tail.nil? + @tail = @head end - - def empty? - return @head.nil? + end + + def remove_first() + raise ArgumentError, "Empty" if self.empty? + + value = @head.data + @head = @head.next + @head.previous = nil + return value + end + + def empty? + return @head.nil? + end + + # method to find if the linked list contains a node with specified value + # returns true if found, false otherwise + # Time Complexity: O(n) + # Space Complexity: O(1) + def search(value) + return false if @head.nil? + return true if @head.data = value + current = @head + until current.data.nil? + return true if current.data = value + current = current.next end - - # method to find if the linked list contains a node with specified value - # returns true if found, false otherwise - # Time Complexity: O(n) - # Space Complexity: O(1) - def search(value) - return false if @head.nil? - return true if @head.data = value - current = @head - until current.data.nil? - return true if current.data = value - current = current.next - end + end + + # method to return the max value in the linked list + # returns the data value and not the node + # Time Complexity: O(n) + # Space Complexity: O(1) + def find_max + return nil if @head.nil? + current = @head + max = current.data + until current.nil? + max = current.data if current.data > max + current = current.next end - - # method to return the max value in the linked list - # returns the data value and not the node - # Time Complexity: O(n) - # Space Complexity: O(1) - def find_max - return nil if @head.nil? - current = @head - max = current.data - until current.nil? - max = current.data if current.data > max - current = current.next + return max + end + + # method to return the min value in the linked list + # returns the data value and not the node + # Time Complexity: O(n) + # Space Complexity: O(1) + def find_min + return nil if @head.nil? + current = @head + min = current.data + until current.nil? + if current.data < min + min = current.data end - return max + current = current.next end - - # method to return the min value in the linked list - # returns the data value and not the node - # Time Complexity: O(n) - # Space Complexity: O(1) - def find_min - return nil if @head.nil? - current = @head - min = current.data - until current.nil? - if current.data < min - min = current.data - end - current = current.next - end - return min + return min + end + + + # method that returns the length of the singly linked list + # Time Complexity: O(n) + # Space Complexity: O(1) + def length + return 0 if @head.nil? + length = 0 + current = @head + until current.nil? + current = current.next + length += 1 end - - - # method that returns the length of the singly linked list - # Time Complexity: O(n) - # Space Complexity: O(1) - def length - return 0 if @head.nil? - length = 0 - current = @head - until current.nil? - current = current.next - length += 1 - end - return length - + return length + + end + + # method that returns the value at a given index in the linked list + # index count starts at 0 + # returns nil if there are fewer nodes in the linked list than the index value + # Time Complexity: O(n) + # Space Complexity: O(1) + def get_at_index(index) + return nil if length <= index + current = @head + count = 0 + until current.nil? + return current.data if count == index + current = current.next + count += 1 end - - # method that returns the value at a given index in the linked list - # index count starts at 0 - # returns nil if there are fewer nodes in the linked list than the index value - # Time Complexity: O(n) - # Space Complexity: O(1) - def get_at_index(index) - return nil if length <= index - current = @head - count = 0 - until current.nil? - return current.data if count == index - current = current.next - count += 1 - end + end + + # method to print all the values in the linked list + # Time Complexity: O(n) + # Space Complexity: O(1) + def visit + current = @head + until current.nil? + puts current.data + current = current.next end - - # method to print all the values in the linked list - # Time Complexity: O(n) - # Space Complexity: O(1) - def visit - current = @head - until current.nil? - puts current.data - current = current.next - end + end + + # method to delete the first node found with specified value + # Time Complexity: O(n) where n is the number of nodes + # Space Complexity: O(1) + def delete(value) + return if @head.nil? + current = @head + + if current.data == value + @head = current.next + @head.previous = nil unless @head.nil? + return end - - # method to delete the first node found with specified value - # Time Complexity: O(n) where n is the number of nodes - # Space Complexity: O(1) - def delete(value) - return if @head.nil? - current = @head - + + prev = current + until current.nil? if current.data == value - @head = current.next - @head.previous = nil unless @head.nil? - return + prev.next = current.next + current.next.previous = prev unless current.next.nil? + @tail = prev if @tail == current + else + prev = current end - + current = current.next + end + end + + # method to reverse the singly linked list + # note: the nodes should be moved and not just the values in the nodes + # Time Complexity: O(n) where n is the number of nodes + # Space Complexity: O(1) + def reverse + return nil if @head.nil? + prev = nil + current = @head + until current.nil? + temp = current.next + current.next = prev prev = current - until current.nil? - if current.data == value - prev.next = current.next - current.next.previous = prev unless current.next.nil? - @tail = prev if @tail == current - else - prev = current - end - current = current.next - end + current = temp + prev.previous = current + end - - # method to reverse the singly linked list - # note: the nodes should be moved and not just the values in the nodes - # Time Complexity: O(n) where n is the number of nodes - # Space Complexity: O(1) - def reverse - return nil if @head.nil? - prev = nil - current = @head - until current.nil? - temp = current.next - current.next = prev - prev = current - current = temp - prev.previous = current - - end - - @head = prev - + + @head = prev + + end + + + ## Advanced Exercises + # returns the value at the middle element in the singly linked list + # Time Complexity: O(n) + # Space Complexity: O(1) + def find_middle_value + return nil if @head.nil? + current = @head + if length % 2 == 0 + return nil + else + middle_index = length / 2 end - - - ## Advanced Exercises - # returns the value at the middle element in the singly linked list - # Time Complexity: O(n) - # Space Complexity: O(1) - def find_middle_value - return nil if @head.nil? - current = @head - if length % 2 == 0 - return nil - else - middle_index = length / 2 - end - index = 0 - until current.nil? - return current.data if index == middle_index - current = current.next - index += 1 - end - + index = 0 + until current.nil? + return current.data if index == middle_index + current = current.next + index += 1 end - - # find the nth node from the end and return its value - # assume indexing starts at 0 while counting to n - # Time Complexity: O(n) - # Space Complexity: O(1) - def find_nth_from_end(n) - return nil if @head.nil? - current = @head - index = 0 - until current.nil? - if index == length - n - 1 - return current.data - end - index += 1 - current = current.next + + end + + # find the nth node from the end and return its value + # assume indexing starts at 0 while counting to n + # Time Complexity: O(n) + # Space Complexity: O(1) + def find_nth_from_end(n) + return nil if @head.nil? + current = @head + index = 0 + until current.nil? + if index == length - n - 1 + return current.data end + index += 1 + current = current.next end - - # checks if the linked list has a cycle. A cycle exists if any node in the - # linked list links to a node already visited. - # returns true if a cycle is found, false otherwise. - # Time Complexity: O(n) - # Space Complexity: O(1) - def has_cycle - return nil if @head.nil? - slow_p = @head - fast_p = @head - while slow_p != nil && fast_p != nil and fast_p.next != nil - slow_p = slow_p.next - fast_p = fast_p.next.next - if slow_p == fast_p - return true - end - return false + end + + # checks if the linked list has a cycle. A cycle exists if any node in the + # linked list links to a node already visited. + # returns true if a cycle is found, false otherwise. + # Time Complexity: O(n) + # Space Complexity: O(1) + def has_cycle + return nil if @head.nil? + slow_p = @head + fast_p = @head + while slow_p != nil && fast_p != nil and fast_p.next != nil + slow_p = slow_p.next + fast_p = fast_p.next.next + if slow_p == fast_p + return true end + return false end - - - # Additional Exercises - # returns the value in the first node - # returns nil if the list is empty - # Time Complexity: O(1) - # Space Complexity: O(1) - def get_first - return nil if @head.nil? - return @head.data - end - - # method that inserts a given value as a new last node in the linked list - # Time Complexity: O(n) where n is the number of nodes - # Space Complexity: O(1) - def add_last(value) - new_node = Node.new(value) - if @head.nil? - self.add_first(value) - return - end - @tail.next = new_node - new_node.previous = @tail - @tail = new_node + end + + + # Additional Exercises + # returns the value in the first node + # returns nil if the list is empty + # Time Complexity: O(1) + # Space Complexity: O(1) + def get_first + return nil if @head.nil? + return @head.data + end + + # method that inserts a given value as a new last node in the linked list + # Time Complexity: O(n) where n is the number of nodes + # Space Complexity: O(1) + def add_last(value) + new_node = Node.new(value) + if @head.nil? + self.add_first(value) + return end - - def remove_last() - value = @tail.data - if @head == @tail - @head = @tail = nil - else - @tail = @tail.previous - @tail.next = nil - end - - return value + @tail.next = new_node + new_node.previous = @tail + @tail = new_node + end + + def remove_last() + value = @tail.data + if @head == @tail + @head = @tail = nil + else + @tail = @tail.previous + @tail.next = nil end - - # method that returns the value of the last node in the linked list - # returns nil if the linked list is empty - # Time Complexity: O(n) where n is the number of nodes - # Space Complexity: O(1) - def get_last - return nil if @head.nil? - return @tail.data + + return value + end + + # method that returns the value of the last node in the linked list + # returns nil if the linked list is empty + # Time Complexity: O(n) where n is the number of nodes + # Space Complexity: O(1) + def get_last + return nil if @head.nil? + return @tail.data + end + + # method to insert a new node with specific data value, assuming the linked + # list is sorted in ascending order + # Time Complexity: O(n) + # Space Complexity: O(1) + def insert_ascending(value) + new_node = Node.new(value) + add_first(value) if @head.nil? + current = @head + if current.data > new_node.data + temp = @head + @head = new_node + temp.previous = @head + new_node.next = temp end - - # method to insert a new node with specific data value, assuming the linked - # list is sorted in ascending order - # Time Complexity: O(n) - # Space Complexity: O(1) - def insert_ascending(value) - new_node = Node.new(value) - add_first(value) if @head.nil? - current = @head - if current.data > new_node.data - temp = @head - @head = new_node - temp.previous = @head + + until current.nil? + if current.data <= value && current.next.data > value + temp = current.next + current.next = new_node new_node.next = temp + new_node.previous = current + temp.previous = new_node + return end - - until current.nil? - if current.data <= value && current.next.data > value - temp = current.next - current.next = new_node - new_node.next = temp - new_node.previous = current - temp.previous = new_node - return - end - current = current.next - end + current = current.next end - - # Helper method for tests - # Creates a cycle in the linked list for testing purposes - # Assumes the linked list has at least one node - def create_cycle - return if @head == nil # don't do anything if the linked list is empty - - # navigate to last node - current = @head - while current.next != nil - current = current.next - end - - current.next = @head # make the last node link to first node + end + + # Helper method for tests + # Creates a cycle in the linked list for testing purposes + # Assumes the linked list has at least one node + def create_cycle + return if @head == nil # don't do anything if the linked list is empty + + # navigate to last node + current = @head + while current.next != nil + current = current.next end - - def to_s - list = [] - - current = @head - until current.nil? - list << current.data - current = current.next - end - - return list.to_s + + current.next = @head # make the last node link to first node + end + + def to_s + list = [] + + current = @head + until current.nil? + list << current.data + current = current.next end + + return list.to_s + end end \ No newline at end of file diff --git a/lib/problems.rb b/lib/problems.rb index 5085953d..14b2240e 100644 --- a/lib/problems.rb +++ b/lib/problems.rb @@ -4,6 +4,7 @@ # Space Complexity: ? def balanced(string) raise NotImplementedError, "Not implemented yet" + # One by one put each bracket into a stack. If the bottom is a close (right) bracket, return false. If a right bracket closes a left bracket, both get popped of the stack. If all brackets get popped off and the stack is empty, the expression is balanced. end # Time Complexity: ? diff --git a/lib/queue.rb b/lib/queue.rb index 828217c6..2806aeae 100644 --- a/lib/queue.rb +++ b/lib/queue.rb @@ -1,30 +1,46 @@ class Queue - + def initialize - # @store = ... - raise NotImplementedError, "Not yet implemented" + @store = Array.new(10) + @front = @back = -1 end - + def enqueue(element) - raise NotImplementedError, "Not yet implemented" + if @front == -1 && @back == -1 + @front = 0 + @back = 1 + end + if @front == @back + puts 'queue is full, sorry!' + return + end + @store[@back-1] = element + @back = (@back + 1) % @store.length # to get back to index 0 end - + def dequeue - raise NotImplementedError, "Not yet implemented" + if @front == -1 && @back == -1 + puts 'queue is empty, sorry!' + return + end + value = @store[@front] + @front = (@front + 1) % @store.length + return value end - + def front raise NotImplementedError, "Not yet implemented" end - + def size raise NotImplementedError, "Not yet implemented" end - + def empty? - raise NotImplementedError, "Not yet implemented" + return true if @front == -1 && @back == -1 + return false end - + def to_s return @store.to_s end diff --git a/lib/stack.rb b/lib/stack.rb index cfc6ef0f..153321d7 100644 --- a/lib/stack.rb +++ b/lib/stack.rb @@ -1,21 +1,24 @@ class Stack def initialize - # @store = ... - raise NotImplementedError, "Not yet implemented" + @store = LinkedList.new end - + def push(element) - raise NotImplementedError, "Not yet implemented" + @store.add_last(element) end - + def pop - raise NotImplementedError, "Not yet implemented" + temp = @store.remove_last() + if !temp + puts "stack is empty" + else return temp + end end - + def empty? - raise NotImplementedError, "Not yet implemented" + return @store.empty? end - + def to_s return @store.to_s end diff --git a/test/queue_test.rb b/test/queue_test.rb index 8a7dcd9c..d7076b05 100644 --- a/test/queue_test.rb +++ b/test/queue_test.rb @@ -7,65 +7,67 @@ describe "Test Queue Implementation" do it "creates a Queue" do q = Queue.new - q.class.must_equal Queue + expect(q.class).must_equal Queue end - + it "adds something to an empty Queue" do - skip q = Queue.new q.enqueue(10) - q.to_s.must_equal "[10]" + expect(q.to_s).must_equal "[10]" end - + it "adds multiple somethings to a Queue" do - skip q = Queue.new q.enqueue(10) q.enqueue(20) q.enqueue(30) - q.to_s.must_equal "[10, 20, 30]" + expect(q.to_s).must_equal "[10, 20, 30]" end - + it "starts the size of a Queue at 0" do - skip q = Queue.new - q.empty?.must_equal true + expect(q.empty?).must_equal true end - + + it "a Queue is empty after removing all the elements" do + q = Queue.new + q.enqueue(5) + q.enqueue(6) + expect( expect(q.dequeue) ).must_equal 5 + expect( expect(q.dequeue) ).must_equal 6 + expect(q.empty?).must_equal true + end + it "removes something from the Queue" do - skip q = Queue.new q.enqueue(5) removed = q.dequeue - removed.must_equal 5 - q.empty?.must_equal true + expect(removed).must_equal 5 + expect(q.empty?).must_equal true end - + it "removes the right something (LIFO)" do - skip q = Queue.new q.enqueue(5) q.enqueue(3) q.enqueue(7) removed = q.dequeue - removed.must_equal 5 - q.to_s.must_equal "[3, 7]" + expect(removed).must_equal 5 + expect(q.to_s).must_equal "[3, 7]" end - + it "properly adjusts the size with enqueueing and dequeueing" do - skip q = Queue.new - q.empty?.must_equal true + expect(q.empty?).must_equal true q.enqueue(-1) q.enqueue(-60) - q.empty?.must_equal false + expect(q.empty?).must_equal false q.dequeue q.dequeue - q.empty?.must_equal true + expect(q.empty?).must_equal true end - + it "returns the front element in the Queue" do - skip q = Queue.new q.enqueue(40) q.enqueue(22) @@ -100,7 +102,7 @@ q.enqueue(200) q.enqueue(210) q.dequeue - - expect(q.to_s).must_equal('[40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240]') + + expect(q.to_s).must_equal('[30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200]') end end diff --git a/test/stack_test.rb b/test/stack_test.rb index df5046c8..6f63f7cb 100644 --- a/test/stack_test.rb +++ b/test/stack_test.rb @@ -1,53 +1,49 @@ require 'minitest/autorun' require 'minitest/reporters' require_relative '../lib/stack' +require_relative '../lib/linked_list.rb' Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new describe "Test Stack Implementation" do it "creates a Stack" do s = Stack.new - s.class.must_equal Stack + expect(s.class).must_equal Stack end - + it "pushes something onto a empty Stack" do - skip s = Stack.new s.push(10) - s.to_s.must_equal "[10]" + expect(s.to_s).must_equal "[10]" end - + it "pushes multiple somethings onto a Stack" do - skip s = Stack.new s.push(10) s.push(20) s.push(30) - s.to_s.must_equal "[10, 20, 30]" + expect(s.to_s).must_equal "[10, 20, 30]" end - + it "starts the stack empty" do - skip s = Stack.new - s.empty?.must_equal true + expect(s.empty?).must_equal true end - + it "removes something from the stack" do - skip s = Stack.new s.push(5) removed = s.pop removed.must_equal 5 - s.empty?.must_equal true + expect(s.empty?).must_equal true end - + it "removes the right something (LIFO)" do - skip s = Stack.new s.push(5) s.push(3) s.push(7) removed = s.pop removed.must_equal 7 - s.to_s.must_equal "[5, 3]" + expect(s.to_s).must_equal "[5, 3]" end end \ No newline at end of file