From 2df6da02726c30e373b32419df09ef4d29178822 Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Thu, 4 Oct 2018 10:17:38 -0600 Subject: [PATCH 01/15] assignment completion --- .DS_Store | Bin 0 -> 6148 bytes 01-data-structures/.DS_Store | Bin 0 -> 6148 bytes .../line/line.rb | 9 ++++++- .../line/line_answers.txt | 23 ++++++++++++++++++ .../line/line_spec.rb | 4 +-- .../screen/pixel.rb | 12 +++++++++ .../screen/pixel_spec.rb | 12 ++++----- .../screen/screen.rb | 13 +++++++++- .../screen/screen_answers.txt | 12 +++++++++ .../screen/screen_spec.rb | 2 +- 10 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 .DS_Store create mode 100644 01-data-structures/.DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..61190987751e14f9ebda5129f8aa0770b7024463 GIT binary patch literal 6148 zcmeHK&59H;5U$LQni&xX5!Pcaf`<`ib{F>`LNl(1y$LOPP}%L?9^8huv-FRHjwAgT z`bNHikE35DnH5=uJq;>VQ2DBpstWlMk}e`rvo@O&jfhA?8G8dXzY!j1y&%2NvjtQx zM?wuHbf0RV$iKh<@7*n$&=k9tVefwKUqvmQ;Jc-Y=2RaR_9QKA3V%K<525$IJArk{ z9O zl0MJpi=)x)$F^*eyqs4qIM3#AdG#VMGrO4Cw#;gmC-wtc5A@(@w7p#J?2OIs-gGrK z%l-Yy*zD~-Sgi(n`|kA7;qlw|AC@0ipFX?Qk;3_Qax>r>zQDK?fA8X|ENuA({_9-p z9D>4tFdz(Unt^Z+>Fb-GSmqN3gn_@F0lps$lraj}d309?8dm}U`{;H8n|}{E#srK4 zb{;VTQ9cytLscj-ln+P034T$)&Z7?}6^aiPW>%p>QEqnRH_n|@eGU@a3oY4%7+y X4I98HVCNA%5cv^sG)N;1Y?Of?am#5d literal 0 HcmV?d00001 diff --git a/01-data-structures/.DS_Store b/01-data-structures/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..83496f7f59f6effe3e90933589641dc2da0e98e6 GIT binary patch literal 6148 zcmeHK&2G~`5T0!VI6B635i1@<&XA&kfKlyy&)OF0Z?n#7O`sV)IUUR2+DLe7y;K^dhKP`NhRG?)mO2>fdi;In&&I@F~$MYMc=k8qYFoaF>P1+a}%?ZNV3 zl7bI6d;?)W>}MF?j&J_e~0{OY-4Q^NIHH*`LHwUUWKN#Kvar+VvZj z)vy}38n4`OI&}-LDD#n*z2MptuNeE4ZCdp9{V#v$q zQ4*xnQCcQJF6VJohh^2R`hne?&3e6-(;sx_EoZj7+i5w2{?2?}x0-jm5BCq>oSx0z z&EKEP)sw*YQOcIaAMg>zrNsZOn8d9!1ysd=P0pHP@ABZf!(I=>aGzVF5ut) z4Zm06f35H>_}>AaZ>5mEua1|y^n7WTf_{ZW?@8M!z@J5czYh+Saj0>j zP<}d4$R_}>hGr?S`TA#$qj9Klp%6U~p{PJb75a%G6dmo39yipuP^jo6^y5Ql&qBXY zg!GR29XXuDP@ySJ1WW{0Be1EeHsAk`fBpVnC7GIufQi6=6#-G(bN5DAlD=El7RPt3 u13iSY@VJFSNkO5nV`=bJd>bkSeGVJIp~i(mv_Q;{fDD5vOa%UF1il03fXKH1 literal 0 HcmV?d00001 diff --git a/01-data-structures/01-introduction-to-data-structures/line/line.rb b/01-data-structures/01-introduction-to-data-structures/line/line.rb index 84bfe59e..22d5a316 100644 --- a/01-data-structures/01-introduction-to-data-structures/line/line.rb +++ b/01-data-structures/01-introduction-to-data-structures/line/line.rb @@ -9,26 +9,33 @@ def initialize end def join(person) + members.push(person) end def leave(person) + members.delete(person) end def front + members.first end def middle + members[members.length / 2] end def back + members.last end def search(person) + members.detect {|e| e === person} end private def index(person) + members.find_index(person) end -end \ No newline at end of file +end diff --git a/01-data-structures/01-introduction-to-data-structures/line/line_answers.txt b/01-data-structures/01-introduction-to-data-structures/line/line_answers.txt index e69de29b..46398e69 100644 --- a/01-data-structures/01-introduction-to-data-structures/line/line_answers.txt +++ b/01-data-structures/01-introduction-to-data-structures/line/line_answers.txt @@ -0,0 +1,23 @@ + For this challenge regarding the line at an amusement park I opted to use an +array as the data structure. I came to this decision as an array is already much +like a line. + + You can easily add "people" to the end of the "line" using the array.push +method, similar to people joining a real world line at the end. An array of +is also linear like a line, and using some basic ruby method you can modify the +array to show people leaving and entering the line in addition to seeing who is +first, last and in the middle. + + Developers would be able to access and manipulate this data by using Ruby array +method in addition to searching by index. Developers could also search by name +using the detect method Ruby provides. + + I believe that an array was the right solution. I can also envision arrays +being a useful data structure for other situations such as a to-do list of items, +or the midi values and their related notes on a piano. Some other examples that +come to mind would be a repair queue at a phone shop, storing high scores on +sequential levels of an arcade game, etc. The list could go on and on as there +is much real-world data that an array could represent. + + While arrays are a more straight forward and simple data structure their use +and ability to represent data is very valuable to developers. diff --git a/01-data-structures/01-introduction-to-data-structures/line/line_spec.rb b/01-data-structures/01-introduction-to-data-structures/line/line_spec.rb index b755dabb..13435d11 100644 --- a/01-data-structures/01-introduction-to-data-structures/line/line_spec.rb +++ b/01-data-structures/01-introduction-to-data-structures/line/line_spec.rb @@ -1,6 +1,6 @@ include RSpec -require_relative 'line' +require_relative 'line' RSpec.describe Line, type: Class do let(:line) { Line.new } @@ -59,4 +59,4 @@ end end -end \ No newline at end of file +end diff --git a/01-data-structures/01-introduction-to-data-structures/screen/pixel.rb b/01-data-structures/01-introduction-to-data-structures/screen/pixel.rb index e286557e..5e087197 100644 --- a/01-data-structures/01-introduction-to-data-structures/screen/pixel.rb +++ b/01-data-structures/01-introduction-to-data-structures/screen/pixel.rb @@ -12,11 +12,23 @@ class Pixel def initialize(red, green, blue, x, y) + @red = validate_color(red) + @green = validate_color(green) + @blue = validate_color(blue) + @x = x + @y = y end private def validate_color(color) + if color < 0 + 0 + elsif color > 255 + 255 + else + color + end end end diff --git a/01-data-structures/01-introduction-to-data-structures/screen/pixel_spec.rb b/01-data-structures/01-introduction-to-data-structures/screen/pixel_spec.rb index b3ab426e..3136cbed 100644 --- a/01-data-structures/01-introduction-to-data-structures/screen/pixel_spec.rb +++ b/01-data-structures/01-introduction-to-data-structures/screen/pixel_spec.rb @@ -4,24 +4,24 @@ describe "#initialize" do it "creates a pixel with the specified parameters" do pixel = Pixel.new(255, 200, 160, 5, 7) - + expect(pixel.red).to eq 255 expect(pixel.green).to eq 200 expect(pixel.blue).to eq 160 expect(pixel.x).to eq 5 expect(pixel.y).to eq 7 end - + it "corrects a red value if it's less than 0" do pixel = Pixel.new(-7, 100, 100, 5, 5) expect(pixel.red).to eq 0 end - + it "corrects a blue value if it's less than 0" do pixel = Pixel.new(100, -10, 100, 5, 5) expect(pixel.green).to eq 0 end - + it "corrects a green value if it's less than 0" do pixel = Pixel.new(100, 100, -12, 5, 5) expect(pixel.blue).to eq 0 @@ -31,12 +31,12 @@ pixel = Pixel.new(256, 100, 100, 5, 5) expect(pixel.red).to eq 255 end - + it "corrects a green value if it's greater than 255" do pixel = Pixel.new(100, 258, 100, 5, 5) expect(pixel.green).to eq 255 end - + it "corrects a blue value if it's greater than 255" do pixel = Pixel.new(100, 100, 300, 5, 5) expect(pixel.blue).to eq 255 diff --git a/01-data-structures/01-introduction-to-data-structures/screen/screen.rb b/01-data-structures/01-introduction-to-data-structures/screen/screen.rb index 8a0aee67..32b0acf1 100644 --- a/01-data-structures/01-introduction-to-data-structures/screen/screen.rb +++ b/01-data-structures/01-introduction-to-data-structures/screen/screen.rb @@ -6,18 +6,29 @@ class Screen attr_accessor :matrix def initialize(width, height) + @matrix = Array.new(width) { Array.new(height, 0) } + @height = height + @width = width end # Insert a Pixel at x, y def insert(pixel, x, y) + @matrix[x][y] = pixel end def at(x, y) + inbounds(x, y) end private def inbounds(x, y) + if x > @width || y > @height || x < 0 || y < 0 + nil + else + @matrix[x][y] + end + end -end \ No newline at end of file +end diff --git a/01-data-structures/01-introduction-to-data-structures/screen/screen_answers.txt b/01-data-structures/01-introduction-to-data-structures/screen/screen_answers.txt index e69de29b..ca244897 100644 --- a/01-data-structures/01-introduction-to-data-structures/screen/screen_answers.txt +++ b/01-data-structures/01-introduction-to-data-structures/screen/screen_answers.txt @@ -0,0 +1,12 @@ + For this challenge regarding the pixel and screen I opted to use a matrix made +up of an array containing arrays. This allowed me to represent the height and +width of the screen that will then contain the pixels. + + This data structure will allow for easy access to the data in the matrix. By +using matrix[coordinate-x][coordinate-y] you can easily manipulate or retrieve the data in the structure. Developers +would be able to easily search for pixels by coordinates. + + This data structure could be useful for other real world data representations +such as any game that utilizes a grid, for example battleship, connect 4 or +tick tack toe. In addition previous checkpoints showed that a matrix can be used +to represent graph data such as vertices and edges. diff --git a/01-data-structures/01-introduction-to-data-structures/screen/screen_spec.rb b/01-data-structures/01-introduction-to-data-structures/screen/screen_spec.rb index f05becb2..45a2e008 100644 --- a/01-data-structures/01-introduction-to-data-structures/screen/screen_spec.rb +++ b/01-data-structures/01-introduction-to-data-structures/screen/screen_spec.rb @@ -9,7 +9,7 @@ screen.insert(pixel, 1, 1) expect(screen.at(1, 1)).to eq pixel - end + end it "retains color information upon insertion" do pixel = Pixel.new(255, 200, 175, 1, 1) From 70ea231014b860cc07bccdc756d0fd2e4fabdd9a Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Thu, 4 Oct 2018 15:53:41 -0600 Subject: [PATCH 02/15] assignment completion --- .../02-stacks-and-queues/myqueue/myqueue.rb | 15 ++++++++++++++- .../myqueue/myqueue_answers.txt | 14 ++++++++++++++ .../02-stacks-and-queues/mystack/mystack.rb | 13 ++++++++++++- .../mystack/mystack_answers.txt | 12 ++++++++++++ .../02-stacks-and-queues/mystack/mystack_spec.rb | 8 +++++++- 5 files changed, 59 insertions(+), 3 deletions(-) diff --git a/01-data-structures/02-stacks-and-queues/myqueue/myqueue.rb b/01-data-structures/02-stacks-and-queues/myqueue/myqueue.rb index 3b66c08b..8f0817ef 100644 --- a/01-data-structures/02-stacks-and-queues/myqueue/myqueue.rb +++ b/01-data-structures/02-stacks-and-queues/myqueue/myqueue.rb @@ -8,11 +8,24 @@ def initialize end def enqueue(element) + @queue << element + @head = @queue[0] + @tail = @queue[-1] end def dequeue + temp = @head + @queue.delete_at(0) + @head = @queue[0] + @tail = @queue[-1] + temp end def empty? + if(@queue.length === 0) + true + else + false + end end -end \ No newline at end of file +end diff --git a/01-data-structures/02-stacks-and-queues/myqueue/myqueue_answers.txt b/01-data-structures/02-stacks-and-queues/myqueue/myqueue_answers.txt index e69de29b..f72c15d4 100644 --- a/01-data-structures/02-stacks-and-queues/myqueue/myqueue_answers.txt +++ b/01-data-structures/02-stacks-and-queues/myqueue/myqueue_answers.txt @@ -0,0 +1,14 @@ + I have created a queue and based on the tests, in addition to my understanding +I believe it has what is necessary to function properly as a queue. + + My enqueue method appends the element to the end of the array. It will then +set the new head as the element at queue[0] and the tail as element at queue[-1]. + + My dequeue method allows for FIFO as it will remove the first item in the queue +after storing it temporarily(so that it can be returned). Following the removal of +the first element it will set the new head to the new item at queue[0] and the new +tail to queue[-1]. It will then return the previous head. + + My empty method will check to see if the queue length is equal to zero and if +it is we know the queue is empty and the method will return true. If not equal +to zero then the method will return false as it is not empty diff --git a/01-data-structures/02-stacks-and-queues/mystack/mystack.rb b/01-data-structures/02-stacks-and-queues/mystack/mystack.rb index ff1ebe97..61a96e0c 100644 --- a/01-data-structures/02-stacks-and-queues/mystack/mystack.rb +++ b/01-data-structures/02-stacks-and-queues/mystack/mystack.rb @@ -7,11 +7,22 @@ def initialize end def push(item) + self.top = item + @stack << item end def pop + temp = self.top + @stack.delete_at(-1) + self.top = @stack[-1] + temp end def empty? + if(@stack.length === 0) + true + else + false + end end -end \ No newline at end of file +end diff --git a/01-data-structures/02-stacks-and-queues/mystack/mystack_answers.txt b/01-data-structures/02-stacks-and-queues/mystack/mystack_answers.txt index e69de29b..c0e80d9e 100644 --- a/01-data-structures/02-stacks-and-queues/mystack/mystack_answers.txt +++ b/01-data-structures/02-stacks-and-queues/mystack/mystack_answers.txt @@ -0,0 +1,12 @@ + With my current understanding of a stack I believe my solution meets the necessary +requirements. + + For my push method I appended the item to the end of the stack. From there my +pop method will temporarily store the current top then delete the last element +in the array. It will then reset the top to the new last element and return +the old top. + + The empty? method will check to see if the array length is equal to zero and +if it is it means the stack is empty and will return true. If the length is not +equal to zero then that will mean there is at least one element in the array +and will return false. diff --git a/01-data-structures/02-stacks-and-queues/mystack/mystack_spec.rb b/01-data-structures/02-stacks-and-queues/mystack/mystack_spec.rb index c0d1af80..37f2a39b 100644 --- a/01-data-structures/02-stacks-and-queues/mystack/mystack_spec.rb +++ b/01-data-structures/02-stacks-and-queues/mystack/mystack_spec.rb @@ -40,9 +40,15 @@ expect(stack.empty?).to eq true end + it "returns true when the stack is empty" do + stack.push("Rob") + stack.pop + expect(stack.empty?).to eq true + end + it "returns false when the stack is not empty" do stack.push("Rob") expect(stack.empty?).to eq false end end -end \ No newline at end of file +end From 76e7b01fdc929a7d5dfa6bbaf35729b360d535e8 Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Mon, 8 Oct 2018 16:06:13 -0600 Subject: [PATCH 03/15] linked list started --- .../03-linked-lists/linked-lists-answers.txt | 4 ++ .../03-linked-lists/linked_list.rb | 66 ++++++++++++++++++- .../03-linked-lists/linked_list_spec.rb | 2 +- 01-data-structures/03-linked-lists/node.rb | 4 +- 4 files changed, 73 insertions(+), 3 deletions(-) diff --git a/01-data-structures/03-linked-lists/linked-lists-answers.txt b/01-data-structures/03-linked-lists/linked-lists-answers.txt index e69de29b..ba89be7f 100644 --- a/01-data-structures/03-linked-lists/linked-lists-answers.txt +++ b/01-data-structures/03-linked-lists/linked-lists-answers.txt @@ -0,0 +1,4 @@ +spacial Locality involves accessing items that are close together in memory, as +in an array. This benefits performance as it limits the number of RAM lookups which +are more time consuming. + diff --git a/01-data-structures/03-linked-lists/linked_list.rb b/01-data-structures/03-linked-lists/linked_list.rb index 5ee2a533..3dfea23c 100644 --- a/01-data-structures/03-linked-lists/linked_list.rb +++ b/01-data-structures/03-linked-lists/linked_list.rb @@ -4,27 +4,91 @@ class LinkedList attr_accessor :head attr_accessor :tail + def initialize + @head = nil + @tail = @head + end + # This method creates a new `Node` using `data`, and inserts it at the end of the list. def add_to_tail(node) + if !@head + @head = node + @tail = node + else + currentNode = @head + + while(currentNode.next != nil) + currentNode = currentNode.next + end + + currentNode.next = node + @tail = node + end end # This method removes the last node in the lists and must keep the rest of the list intact. def remove_tail + currentNode = @head + + while currentNode.next + previousNode = currentNode + currentNode = currentNode.next + end + + if @head.next + currentNode = nil + previousNode.next = nil + @tail = previousNode + else + @head = nil + @tail = nil + end + end # This method prints out a representation of the list. def print + currentNode = @head + + while currentNode + puts currentNode.data + currentNode = currentNode.next + end end # This method removes `node` from the list and must keep the rest of the list intact. def delete(node) + currentNode = @head + + if(node == @head) + remove_front + + elsif(node == @tail) + remove_tail + + else + + while currentNode != node + previousNode = currentNode + currentNode = currentNode.next + end + + previousNode.next = currentNode.next + currentNode = nil + end end # This method adds `node` to the front of the list and must set the list's head to `node`. def add_to_front(node) + old_head = @head + @head = node + @head.next = old_head end # This method removes and returns the first node in the Linked List and must set Linked List's head to the second node. def remove_front + front = @head + @head = @head.next + front end -end \ No newline at end of file +end diff --git a/01-data-structures/03-linked-lists/linked_list_spec.rb b/01-data-structures/03-linked-lists/linked_list_spec.rb index cabef225..bf236ace 100644 --- a/01-data-structures/03-linked-lists/linked_list_spec.rb +++ b/01-data-structures/03-linked-lists/linked_list_spec.rb @@ -89,4 +89,4 @@ expect(llist.head).to eq nil end end -end \ No newline at end of file +end diff --git a/01-data-structures/03-linked-lists/node.rb b/01-data-structures/03-linked-lists/node.rb index 016acb90..326bdcc0 100644 --- a/01-data-structures/03-linked-lists/node.rb +++ b/01-data-structures/03-linked-lists/node.rb @@ -3,5 +3,7 @@ class Node attr_accessor :data def initialize(data) + @data = data + @next = nil end -end \ No newline at end of file +end From 8d60abe511f835d05d788f290da3f653f8b642c0 Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Tue, 9 Oct 2018 12:53:46 -0600 Subject: [PATCH 04/15] assignment completion --- .../03-linked-lists/linked-lists-answers.txt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/01-data-structures/03-linked-lists/linked-lists-answers.txt b/01-data-structures/03-linked-lists/linked-lists-answers.txt index ba89be7f..28d717d9 100644 --- a/01-data-structures/03-linked-lists/linked-lists-answers.txt +++ b/01-data-structures/03-linked-lists/linked-lists-answers.txt @@ -1,4 +1,15 @@ -spacial Locality involves accessing items that are close together in memory, as + Spacial Locality involves accessing items that are close together in memory, as in an array. This benefits performance as it limits the number of RAM lookups which are more time consuming. - + + I have created the benchmark tests for the array and the linked list. I found +array out performed the linked list in all 3 tests. When creating the 10,000 item +array and appending 10,000 items to the linked list the array completed slightly +more then 4 seconds before the linked list. The list had to move through all previous +nodes to add to the tail node, explaining why it took so much longer. Accessing +the 5,000th element and deleting the 5,000 element were much closer as far as time +but the array was still faster in both tests. + + I have attached links to my benchmark tests on repl.it. +Array Benchmarks: https://repl.it/@ConSou/Array-Benchmark +Linked List Benchmarks: https://repl.it/@ConSou/Linked-List-Benchmark From 421fa9004873797828f97bee03d9383ae974a66a Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Tue, 9 Oct 2018 18:13:24 -0600 Subject: [PATCH 05/15] hashclass work --- .../04-hashes-part-1/hash_item.rb | 4 +- .../04-hashes-part-1/hashclass.rb | 36 +++++- .../04-hashes-part-1/hashclass_spec.rb | 114 +++++++++--------- 3 files changed, 95 insertions(+), 59 deletions(-) diff --git a/01-data-structures/04-hashes-part-1/hash_item.rb b/01-data-structures/04-hashes-part-1/hash_item.rb index 4a420212..5953907a 100644 --- a/01-data-structures/04-hashes-part-1/hash_item.rb +++ b/01-data-structures/04-hashes-part-1/hash_item.rb @@ -3,5 +3,7 @@ class HashItem attr_accessor :value def initialize(key, value) + @key = key + @value = value end -end \ No newline at end of file +end diff --git a/01-data-structures/04-hashes-part-1/hashclass.rb b/01-data-structures/04-hashes-part-1/hashclass.rb index e538428a..9a3f0063 100644 --- a/01-data-structures/04-hashes-part-1/hashclass.rb +++ b/01-data-structures/04-hashes-part-1/hashclass.rb @@ -5,23 +5,57 @@ def initialize(size) end def []=(key, value) + index_val = index(key, @items.length) + # p @items[index_val] + # p value + if @items[index_val] === nil || @items[index_val][1] === value + @items[index_val] = [key, value] + else + resize + end end def [](key) + puts "------------------" + p @items + index_val = index(key, @items.length) + @items[index_val][1] end def resize + @items += Array.new(@items.length) + + i = 0 + while i < @items.size + if @items[i] != nil + @items[index(@items[i][0], @items.size)] = [@items[i][0], @items[i][1]] + end + i += 1 + end end # Returns a unique, deterministically reproducible index into an array # We are hashing based on strings, let's use the ascii value of each string as # a starting point. def index(key, size) + i = 0 + hash_code = 0 + + while(i < key.length) + hash_code += key[i].ord + i += 1 + end + + hash_code % size + + puts "------------------" + p hash_code % size end # Simple method to return the number of items in the hash def size + @items.length end -end \ No newline at end of file +end diff --git a/01-data-structures/04-hashes-part-1/hashclass_spec.rb b/01-data-structures/04-hashes-part-1/hashclass_spec.rb index 31b4ced6..9f9b618c 100644 --- a/01-data-structures/04-hashes-part-1/hashclass_spec.rb +++ b/01-data-structures/04-hashes-part-1/hashclass_spec.rb @@ -6,71 +6,71 @@ RSpec.describe HashClass, type: Class do let(:lotr_movies) { HashClass.new(6) } - describe "#index" do - it "creates a hash key based on the string value passed in" do - i = lotr_movies.index("The Lord of the Rings: The Fellowship of the Ring", 6) - expect(i).to eq 5 - end - end - - describe "#key" do - it "returns the sum of the ascii values of the string value" do - key = "test" - expect(lotr_movies.index(key, 6)).to eq 4 - end - end - - describe "#resize" do - it "doubles the size of the array when invoked" do - expect(lotr_movies.size).to eq 6 - lotr_movies.resize - expect(lotr_movies.size).to eq 12 - end - - it "copies existing values properly when the array is resized" do - movies = HashClass.new(30) - movies["A New Hope"] = "Average" - movies["Empire Strikes Back"] = "Excellent" - movies["Return of the Jedi"] = "The Best" - movies.resize - expect(movies.size).to eq 60 - expect(movies["A New Hope"]).to eq "Average" - expect(movies["Empire Strikes Back"]).to eq "Excellent" - expect(movies["Return of the Jedi"]).to eq "The Best" - end - end + # describe "#index" do + # it "creates a hash key based on the string value passed in" do + # i = lotr_movies.index("The Lord of the Rings: The Fellowship of the Ring", 6) + # expect(i).to eq 5 + # end + # end + # + # describe "#key" do + # it "returns the sum of the ascii values of the string value" do + # key = "test" + # expect(lotr_movies.index(key, 6)).to eq 4 + # end + # end + # + # describe "#resize" do + # it "doubles the size of the array when invoked" do + # expect(lotr_movies.size).to eq 6 + # lotr_movies.resize + # expect(lotr_movies.size).to eq 12 + # end + # + # it "copies existing values properly when the array is resized" do + # movies = HashClass.new(30) + # movies["A New Hope"] = "Average" + # movies["Empire Strikes Back"] = "Excellent" + # movies["Return of the Jedi"] = "The Best" + # movies.resize + # expect(movies.size).to eq 60 + # expect(movies["A New Hope"]).to eq "Average" + # expect(movies["Empire Strikes Back"]).to eq "Excellent" + # expect(movies["Return of the Jedi"]).to eq "The Best" + # end + # end describe "hash[key] = value" do - it "does not resize the array when a collision occurs and the values match" do - hash = HashClass.new(1) - hash["key"] = "value" - expect(hash.size).to eq 1 - hash["key"] = "value" - expect(hash.size).to eq 1 - end - - it "resizes the array when a collision occurs and the values do not match" do - hash = HashClass.new(1) - hash["key"] = "value" - expect(hash.size).to eq 1 - hash["key"] = "different" - expect(hash.size).to eq 2 - end + # it "does not resize the array when a collision occurs and the values match" do + # hash = HashClass.new(1) + # hash["key"] = "value" + # expect(hash.size).to eq 1 + # hash["key"] = "value" + # expect(hash.size).to eq 1 + # end + # + # it "resizes the array when a collision occurs and the values do not match" do + # hash = HashClass.new(1) + # hash["key"] = "value" + # expect(hash.size).to eq 1 + # hash["key"] = "different" + # expect(hash.size).to eq 2 + # end it "sets the value of key to value" do lotr_movies["The Lord of the Rings: The Fellowship of the Ring"] = "3 hours, 48 minutes" - lotr_movies["The Lord of the Rings: The Two Towers"] = "3 hours, 55 minutes" + #lotr_movies["The Lord of the Rings: The Two Towers"] = "3 hours, 55 minutes" lotr_movies["The Lord of the Rings: The Return of the King"] = "3 hours, 21 minutes" - lotr_movies["The Hobbit: An Unexpected Journey"] = "3 hours, 2 minutes" - lotr_movies["The Hobbit: The Desolation of Smaug"] = "3 hours, 7 minutes" - lotr_movies["The Hobbit: The Battle of Five Armies"] = "2 hours, 44 minutes" + #lotr_movies["The Hobbit: An Unexpected Journey"] = "3 hours, 2 minutes" + #lotr_movies["The Hobbit: The Desolation of Smaug"] = "3 hours, 7 minutes" + #lotr_movies["The Hobbit: The Battle of Five Armies"] = "2 hours, 44 minutes" expect(lotr_movies["The Lord of the Rings: The Fellowship of the Ring"]).to eq "3 hours, 48 minutes" - expect(lotr_movies["The Lord of the Rings: The Two Towers"]).to eq "3 hours, 55 minutes" + #expect(lotr_movies["The Lord of the Rings: The Two Towers"]).to eq "3 hours, 55 minutes" expect(lotr_movies["The Lord of the Rings: The Return of the King"]).to eq "3 hours, 21 minutes" - expect(lotr_movies["The Hobbit: An Unexpected Journey"]).to eq "3 hours, 2 minutes" - expect(lotr_movies["The Hobbit: The Desolation of Smaug"]).to eq "3 hours, 7 minutes" - expect(lotr_movies["The Hobbit: The Battle of Five Armies"]).to eq "2 hours, 44 minutes" + #expect(lotr_movies["The Hobbit: An Unexpected Journey"]).to eq "3 hours, 2 minutes" + #expect(lotr_movies["The Hobbit: The Desolation of Smaug"]).to eq "3 hours, 7 minutes" + #expect(lotr_movies["The Hobbit: The Battle of Five Armies"]).to eq "2 hours, 44 minutes" end end -end \ No newline at end of file +end From 3d6bdfe69af1d7eb6e00c4af8d85fe2dd4481a5a Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Tue, 9 Oct 2018 20:15:40 -0600 Subject: [PATCH 06/15] hashclass work --- .../04-hashes-part-1/hashclass_spec.rb | 112 +++++++++--------- .../04-hashes-part-1/hashes-1-answers.txt | 15 +++ 2 files changed, 71 insertions(+), 56 deletions(-) diff --git a/01-data-structures/04-hashes-part-1/hashclass_spec.rb b/01-data-structures/04-hashes-part-1/hashclass_spec.rb index 9f9b618c..5c7d0e97 100644 --- a/01-data-structures/04-hashes-part-1/hashclass_spec.rb +++ b/01-data-structures/04-hashes-part-1/hashclass_spec.rb @@ -6,71 +6,71 @@ RSpec.describe HashClass, type: Class do let(:lotr_movies) { HashClass.new(6) } - # describe "#index" do - # it "creates a hash key based on the string value passed in" do - # i = lotr_movies.index("The Lord of the Rings: The Fellowship of the Ring", 6) - # expect(i).to eq 5 - # end - # end - # - # describe "#key" do - # it "returns the sum of the ascii values of the string value" do - # key = "test" - # expect(lotr_movies.index(key, 6)).to eq 4 - # end - # end - # - # describe "#resize" do - # it "doubles the size of the array when invoked" do - # expect(lotr_movies.size).to eq 6 - # lotr_movies.resize - # expect(lotr_movies.size).to eq 12 - # end - # - # it "copies existing values properly when the array is resized" do - # movies = HashClass.new(30) - # movies["A New Hope"] = "Average" - # movies["Empire Strikes Back"] = "Excellent" - # movies["Return of the Jedi"] = "The Best" - # movies.resize - # expect(movies.size).to eq 60 - # expect(movies["A New Hope"]).to eq "Average" - # expect(movies["Empire Strikes Back"]).to eq "Excellent" - # expect(movies["Return of the Jedi"]).to eq "The Best" - # end - # end + describe "#index" do + it "creates a hash key based on the string value passed in" do + i = lotr_movies.index("The Lord of the Rings: The Fellowship of the Ring", 6) + expect(i).to eq 5 + end + end + + describe "#key" do + it "returns the sum of the ascii values of the string value" do + key = "test" + expect(lotr_movies.index(key, 6)).to eq 4 + end + end + + describe "#resize" do + it "doubles the size of the array when invoked" do + expect(lotr_movies.size).to eq 6 + lotr_movies.resize + expect(lotr_movies.size).to eq 12 + end + + it "copies existing values properly when the array is resized" do + movies = HashClass.new(30) + movies["A New Hope"] = "Average" + movies["Empire Strikes Back"] = "Excellent" + movies["Return of the Jedi"] = "The Best" + movies.resize + expect(movies.size).to eq 60 + expect(movies["A New Hope"]).to eq "Average" + expect(movies["Empire Strikes Back"]).to eq "Excellent" + expect(movies["Return of the Jedi"]).to eq "The Best" + end + end describe "hash[key] = value" do - # it "does not resize the array when a collision occurs and the values match" do - # hash = HashClass.new(1) - # hash["key"] = "value" - # expect(hash.size).to eq 1 - # hash["key"] = "value" - # expect(hash.size).to eq 1 - # end - # - # it "resizes the array when a collision occurs and the values do not match" do - # hash = HashClass.new(1) - # hash["key"] = "value" - # expect(hash.size).to eq 1 - # hash["key"] = "different" - # expect(hash.size).to eq 2 - # end + it "does not resize the array when a collision occurs and the values match" do + hash = HashClass.new(1) + hash["key"] = "value" + expect(hash.size).to eq 1 + hash["key"] = "value" + expect(hash.size).to eq 1 + end + + it "resizes the array when a collision occurs and the values do not match" do + hash = HashClass.new(1) + hash["key"] = "value" + expect(hash.size).to eq 1 + hash["key"] = "different" + expect(hash.size).to eq 2 + end it "sets the value of key to value" do lotr_movies["The Lord of the Rings: The Fellowship of the Ring"] = "3 hours, 48 minutes" - #lotr_movies["The Lord of the Rings: The Two Towers"] = "3 hours, 55 minutes" + lotr_movies["The Lord of the Rings: The Two Towers"] = "3 hours, 55 minutes" lotr_movies["The Lord of the Rings: The Return of the King"] = "3 hours, 21 minutes" - #lotr_movies["The Hobbit: An Unexpected Journey"] = "3 hours, 2 minutes" - #lotr_movies["The Hobbit: The Desolation of Smaug"] = "3 hours, 7 minutes" - #lotr_movies["The Hobbit: The Battle of Five Armies"] = "2 hours, 44 minutes" + lotr_movies["The Hobbit: An Unexpected Journey"] = "3 hours, 2 minutes" + lotr_movies["The Hobbit: The Desolation of Smaug"] = "3 hours, 7 minutes" + lotr_movies["The Hobbit: The Battle of Five Armies"] = "2 hours, 44 minutes" expect(lotr_movies["The Lord of the Rings: The Fellowship of the Ring"]).to eq "3 hours, 48 minutes" - #expect(lotr_movies["The Lord of the Rings: The Two Towers"]).to eq "3 hours, 55 minutes" + expect(lotr_movies["The Lord of the Rings: The Two Towers"]).to eq "3 hours, 55 minutes" expect(lotr_movies["The Lord of the Rings: The Return of the King"]).to eq "3 hours, 21 minutes" - #expect(lotr_movies["The Hobbit: An Unexpected Journey"]).to eq "3 hours, 2 minutes" - #expect(lotr_movies["The Hobbit: The Desolation of Smaug"]).to eq "3 hours, 7 minutes" - #expect(lotr_movies["The Hobbit: The Battle of Five Armies"]).to eq "2 hours, 44 minutes" + expect(lotr_movies["The Hobbit: An Unexpected Journey"]).to eq "3 hours, 2 minutes" + expect(lotr_movies["The Hobbit: The Desolation of Smaug"]).to eq "3 hours, 7 minutes" + expect(lotr_movies["The Hobbit: The Battle of Five Armies"]).to eq "2 hours, 44 minutes" end end end diff --git a/01-data-structures/04-hashes-part-1/hashes-1-answers.txt b/01-data-structures/04-hashes-part-1/hashes-1-answers.txt index e69de29b..b7256158 100644 --- a/01-data-structures/04-hashes-part-1/hashes-1-answers.txt +++ b/01-data-structures/04-hashes-part-1/hashes-1-answers.txt @@ -0,0 +1,15 @@ + In order to deal with collisions, this checkpoint instructed us to double the +length of the array and re-map the keys with a new array size. This made it +relatively simple to fix collisions. + + Although this is an easy way to deal with collisions it is not the most effective. +There are a couple things to consider about this option and why it may not be +the best. As you double the size of larger arrays they grow faster and faster, +potentially taking up too much space. This process is also allocating memory +which is not a quick process. In addition if collisions are happening frequently +the items in your array may be very spaced out within that array wasting all the space +in between, which would not be very efficient. + + While doubling the size of an array may work in certain scenarios there are +definitely better solutions to this problem, such as the expansion method described +in the checkpoint (increasing to a prime number near the next largest power of two). From adff546f3207e067ab8c724e301e11a7a6a8d21b Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Wed, 10 Oct 2018 14:41:50 -0600 Subject: [PATCH 07/15] assignment-4 completion --- .../04-hashes-part-1/hashclass.rb | 54 +++++++++---------- .../04-hashes-part-1/hashes-1-answers.txt | 13 ++--- 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/01-data-structures/04-hashes-part-1/hashclass.rb b/01-data-structures/04-hashes-part-1/hashclass.rb index 9a3f0063..ca7ae639 100644 --- a/01-data-structures/04-hashes-part-1/hashclass.rb +++ b/01-data-structures/04-hashes-part-1/hashclass.rb @@ -5,52 +5,46 @@ def initialize(size) end def []=(key, value) - index_val = index(key, @items.length) - # p @items[index_val] - # p value - if @items[index_val] === nil || @items[index_val][1] === value - @items[index_val] = [key, value] - else - resize + index_val = index(key, size) + new_item = @items[index_val] + + if new_item == nil + @items[index_val] = HashItem.new(key, value) + elsif new_item.key != key + while @items[index(key, size)].key != nil && @items[index(key, size)].key != key + resize + i = index(key, size) + break if @items[i] == nil + end + self[key] = value + elsif new_item.key == key && new_item.value != value + resize() + new_item.value = value end end def [](key) - puts "------------------" - p @items - index_val = index(key, @items.length) - @items[index_val][1] + index_val = index(key, size) + @items[index_val].value end def resize - @items += Array.new(@items.length) - - i = 0 - while i < @items.size - if @items[i] != nil - @items[index(@items[i][0], @items.size)] = [@items[i][0], @items[i][1]] + resized_hash = @items += Array.new(size) + + @items.each do |i| + if i != nil + resized_hash[index(i.key, size)] = i end - i += 1 end + @items = resized_hash end # Returns a unique, deterministically reproducible index into an array # We are hashing based on strings, let's use the ascii value of each string as # a starting point. def index(key, size) - i = 0 - hash_code = 0 - - while(i < key.length) - hash_code += key[i].ord - i += 1 - end - - hash_code % size - - puts "------------------" - p hash_code % size + key.sum % size end # Simple method to return the number of items in the hash diff --git a/01-data-structures/04-hashes-part-1/hashes-1-answers.txt b/01-data-structures/04-hashes-part-1/hashes-1-answers.txt index b7256158..c5b35311 100644 --- a/01-data-structures/04-hashes-part-1/hashes-1-answers.txt +++ b/01-data-structures/04-hashes-part-1/hashes-1-answers.txt @@ -1,14 +1,15 @@ In order to deal with collisions, this checkpoint instructed us to double the -length of the array and re-map the keys with a new array size. This made it +length of the array and re-map the keys with the new array size. This made it relatively simple to fix collisions. Although this is an easy way to deal with collisions it is not the most effective. There are a couple things to consider about this option and why it may not be -the best. As you double the size of larger arrays they grow faster and faster, -potentially taking up too much space. This process is also allocating memory -which is not a quick process. In addition if collisions are happening frequently -the items in your array may be very spaced out within that array wasting all the space -in between, which would not be very efficient. +the best. As you double the size of arrays they will grow faster and faster, +potentially taking up too much space. This process also requires allocating more +memory which is not a quick task. In addition if collisions are happening +frequently the array is doubling making it so items in your array are more spaced +out, leaving a lot of nil values in the array and wasting space, which would not be very +efficient. While doubling the size of an array may work in certain scenarios there are definitely better solutions to this problem, such as the expansion method described From 54fdce27625714d70f163ef7e48de12bbe2e7969 Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Wed, 10 Oct 2018 19:46:34 -0600 Subject: [PATCH 08/15] checkpoint-5 work --- .../05-hashes-part-2/open_addressing/node.rb | 4 +- .../open_addressing/open_addressing.rb | 55 ++++++++++++++++- .../separate_chaining/linked_list.rb | 60 ++++++++++++++++++- .../separate_chaining/node.rb | 5 +- .../separate_chaining/separate_chaining.rb | 22 +++++++ 5 files changed, 142 insertions(+), 4 deletions(-) diff --git a/01-data-structures/05-hashes-part-2/open_addressing/node.rb b/01-data-structures/05-hashes-part-2/open_addressing/node.rb index 07f867b7..ce37ad7b 100644 --- a/01-data-structures/05-hashes-part-2/open_addressing/node.rb +++ b/01-data-structures/05-hashes-part-2/open_addressing/node.rb @@ -4,5 +4,7 @@ class Node attr_accessor :value def initialize(key, value) + @key = key + @value = value end -end \ No newline at end of file +end diff --git a/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb b/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb index 30db5754..8fe6efd9 100644 --- a/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb +++ b/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb @@ -1,30 +1,83 @@ +require 'prime' require_relative 'node' class OpenAddressing def initialize(size) + @items = Array.new(size) end def []=(key, value) + index = index(key, size) + + if @items[index] == nil + @items[index] = Node.new(key, value) + elsif next_open_index(0) == -1 + resize + self[key] = value + else + index = next_open_index(index) + if index == -1 + resize + self[key] = value + elsif @items[index] == nil + @items[index] = Node.new(key, value) + end + end end def [](key) + index = 0 + # puts "--------------------" + # p @items + # p index(key, size) + until index == size + if @items[index] == nil + index += 1 + elsif @items[index].key == key + return @items[index].value + else + index += 1 + end + end end # Returns a unique, deterministically reproducible index into an array # We are hashing based on strings, let's use the ascii value of each string as # a starting point. def index(key, size) + key.sum % size end # Given an index, find the next open index in @items def next_open_index(index) + while @items[index] + index += 1 + if index === size + return -1 + end + end + index end # Simple method to return the number of items in the hash def size + @items.length end # Resize the hash def resize + resized_hash = Array.new(size * 2) + + @items.each do |i| + if i != nil + resized_hash[index(i.key, size)] = i + end + end + @items = resized_hash end -end \ No newline at end of file + + def print_hash + p @items + end + +end diff --git a/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb b/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb index 5ee2a533..45eb0e3c 100644 --- a/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb +++ b/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb @@ -6,25 +6,83 @@ class LinkedList # This method creates a new `Node` using `data`, and inserts it at the end of the list. def add_to_tail(node) + if !@head + @head = node + @tail = node + else + currentNode = @head + + while(currentNode.next != nil) + currentNode = currentNode.next + end + + currentNode.next = node + @tail = node + end end # This method removes the last node in the lists and must keep the rest of the list intact. def remove_tail + currentNode = @head + + while currentNode.next + previousNode = currentNode + currentNode = currentNode.next + end + + if @head.next + currentNode = nil + previousNode.next = nil + @tail = previousNode + else + @head = nil + @tail = nil + end end # This method prints out a representation of the list. def print + currentNode = @head + + while currentNode + puts currentNode.data + currentNode = currentNode.next + end end # This method removes `node` from the list and must keep the rest of the list intact. def delete(node) + currentNode = @head + + if(node == @head) + remove_front + + elsif(node == @tail) + remove_tail + + else + + while currentNode != node + previousNode = currentNode + currentNode = currentNode.next + end + + previousNode.next = currentNode.next + currentNode = nil + end end # This method adds `node` to the front of the list and must set the list's head to `node`. def add_to_front(node) + old_head = @head + @head = node + @head.next = old_head end # This method removes and returns the first node in the Linked List and must set Linked List's head to the second node. def remove_front + front = @head + @head = @head.next + front end -end \ No newline at end of file +end diff --git a/01-data-structures/05-hashes-part-2/separate_chaining/node.rb b/01-data-structures/05-hashes-part-2/separate_chaining/node.rb index 07f867b7..b8724673 100644 --- a/01-data-structures/05-hashes-part-2/separate_chaining/node.rb +++ b/01-data-structures/05-hashes-part-2/separate_chaining/node.rb @@ -4,5 +4,8 @@ class Node attr_accessor :value def initialize(key, value) + @key = key + @value = value + @next = nil end -end \ No newline at end of file +end diff --git a/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb b/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb index 1b46c46d..e1a9d755 100644 --- a/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb +++ b/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb @@ -5,9 +5,20 @@ class SeparateChaining def initialize(size) @max_load_factor = 0.7 + @items = Array.new(size) + @item_count = 0 end def []=(key, value) + # index = index(key, size) + # new_node = Node.new(key, value) + # + # if @items[index] == nil + # @items[index] = new_node + # @head = new_node + # elsif load_factor < @max_load_factor + # @items[index].add_to_tail(new_node) + # end end def [](key) @@ -17,17 +28,28 @@ def [](key) # We are hashing based on strings, let's use the ascii value of each string as # a starting point. def index(key, size) + key.sum % size end # Calculate the current load factor def load_factor + @item_count / size end # Simple method to return the number of items in the hash def size + @items.length end # Resize the hash def resize + resized_hash = Array.new(size * 2) + + @items.each do |i| + if i != nil + resized_hash[index(i.key, size)] = i + end + end + @items = resized_hash end end From b421bc2b4ed810ab75ea3bef25b97e979db353ae Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Thu, 11 Oct 2018 21:07:04 -0600 Subject: [PATCH 09/15] hashes-2 work --- .../hashes-part-2-answers.txt | 16 ++++ .../open_addressing/open_addressing.rb | 52 ++++++++----- .../open_addressing/open_addressing_spec.rb | 12 ++- .../separate_chaining/linked_list.rb | 13 ++-- .../separate_chaining/separate_chaining.rb | 78 ++++++++++++++++--- .../separate_chaining_spec.rb | 2 +- 6 files changed, 133 insertions(+), 40 deletions(-) create mode 100644 01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt diff --git a/01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt b/01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt new file mode 100644 index 00000000..73de2159 --- /dev/null +++ b/01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt @@ -0,0 +1,16 @@ +Q: Describe three collision resolution strategies not mentioned here. + +A: The first collision resolution I found that wasn't mentioned in bloc's curriculum +is the Coalesced hashing strategy. It is described as a mix between chaining and +open addressing. This method allows for better use of space like open addressing. +Each slot gets a single element, and if a collision occurs the node in the slot +stores a link to the next open index value. This allows for a quicker look up like +you get with chaining. + + Another method not mentioned is "Separate chaining with list head cells". It is +very similar to the chaining method we discussed in the checkpoint. The standout +difference is that it stores the first element of each chain in the slot itself, +reducing the pointer traversals by one. While it is a slight difference it could +be valuable to get that extra boost of performance in certain scenarios. + + A third method that wasn't in the curriculum is Hopscotch hashing. diff --git a/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb b/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb index 8fe6efd9..dd5b2463 100644 --- a/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb +++ b/01-data-structures/05-hashes-part-2/open_addressing/open_addressing.rb @@ -1,42 +1,37 @@ -require 'prime' require_relative 'node' class OpenAddressing def initialize(size) @items = Array.new(size) + @item_count = 0.0 end def []=(key, value) index = index(key, size) - if @items[index] == nil + if @items[index] == nil || @items[index].key === key @items[index] = Node.new(key, value) - elsif next_open_index(0) == -1 + elsif next_open_index(index) == -1 resize self[key] = value else - index = next_open_index(index) - if index == -1 - resize - self[key] = value - elsif @items[index] == nil + index = next_open_index(index) @items[index] = Node.new(key, value) - end end + @item_count += 1 + #hash_status end def [](key) - index = 0 - # puts "--------------------" - # p @items - # p index(key, size) + index = index(key, size) + + if @items[index].key == key + return @items[index].value + end until index == size - if @items[index] == nil index += 1 - elsif @items[index].key == key + if @items[index].key == key return @items[index].value - else - index += 1 end end end @@ -70,14 +65,31 @@ def resize @items.each do |i| if i != nil - resized_hash[index(i.key, size)] = i + resized_hash[index(i.key, resized_hash.length)] = i end end @items = resized_hash end - def print_hash - p @items + def load_factor + @item_count / size + end + + def hash_status + j = 0 + p "-------------------" + p "Load Factor: #{load_factor}" + @items.each do |i| + if i != nil + p "Index: #{j}" + p "Key: #{i.key}" + p "Value: #{i.value}" + p "~~~~~~~~~~~~~~~~~" + j += 1 + end + end + p "-------------------" + end end diff --git a/01-data-structures/05-hashes-part-2/open_addressing/open_addressing_spec.rb b/01-data-structures/05-hashes-part-2/open_addressing/open_addressing_spec.rb index 2611b64d..73b3f1d6 100644 --- a/01-data-structures/05-hashes-part-2/open_addressing/open_addressing_spec.rb +++ b/01-data-structures/05-hashes-part-2/open_addressing/open_addressing_spec.rb @@ -42,10 +42,20 @@ hash = OpenAddressing.new(1) hash["key"] = "value" expect(hash.size).to eq 1 - hash["key"] = "second value" + # issues in test, two like keys should not cause a collision. I have added + # additional testing + # hash["key"] = "second value" + # expect(hash.size).to eq 2 + hash["key_two"] = "second value" + expect(hash.size).to eq 2 + hash["key_two"] = "Change value" expect(hash.size).to eq 2 + expect(hash["key_two"]).to eq "Change value" + hash["key_three"] = "Three Value" + expect(hash.size).to eq 4 end + it "sets the value of key to value" do expect(star_wars_movies["Star Wars: The Phantom Menace"]).to eq "Number One" expect(star_wars_movies["Star Wars: Attack of the Clones"]).to eq "Number Two" diff --git a/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb b/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb index 45eb0e3c..d8565a0a 100644 --- a/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb +++ b/01-data-structures/05-hashes-part-2/separate_chaining/linked_list.rb @@ -4,12 +4,13 @@ class LinkedList attr_accessor :head attr_accessor :tail + def initialize(head) + @head = head + @tail = @head + end + # This method creates a new `Node` using `data`, and inserts it at the end of the list. def add_to_tail(node) - if !@head - @head = node - @tail = node - else currentNode = @head while(currentNode.next != nil) @@ -18,7 +19,6 @@ def add_to_tail(node) currentNode.next = node @tail = node - end end # This method removes the last node in the lists and must keep the rest of the list intact. @@ -45,7 +45,8 @@ def print currentNode = @head while currentNode - puts currentNode.data + p "Key: #{currentNode.key}" + p "Value: #{currentNode.value}" currentNode = currentNode.next end end diff --git a/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb b/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb index e1a9d755..8852d7dd 100644 --- a/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb +++ b/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining.rb @@ -6,22 +6,46 @@ class SeparateChaining def initialize(size) @max_load_factor = 0.7 @items = Array.new(size) - @item_count = 0 + @item_count = 0.0 end def []=(key, value) - # index = index(key, size) - # new_node = Node.new(key, value) - # - # if @items[index] == nil - # @items[index] = new_node - # @head = new_node - # elsif load_factor < @max_load_factor - # @items[index].add_to_tail(new_node) - # end + index = index(key, size) + new_node = Node.new(key, value) + + if @items[index] == nil + @items[index] = new_node + + elsif @items[index].instance_variable_defined?(:@next) + ll = LinkedList.new(@items[index]) + ll.add_to_tail(new_node) + @items[index] = ll + + elsif @items[index].instance_variable_defined?(:@head) + @items[index].add_to_tail(new_node) + end + + @item_count += 1 + + if load_factor > @max_load_factor + resize + end + + #hash_status end def [](key) + index = index(key, size) + + if @items[index].instance_variable_defined?(:@head) + current_node = @items[index].head + until current_node.key == key + current_node = current_node.next + end + return current_node.value + else + @items[index].value + end end # Returns a unique, deterministically reproducible index into an array @@ -46,10 +70,40 @@ def resize resized_hash = Array.new(size * 2) @items.each do |i| - if i != nil - resized_hash[index(i.key, size)] = i + if i != nil && i.instance_variable_defined?(:@next) + resized_hash[index(i.key, resized_hash.length)] = i + elsif i.instance_variable_defined?(:@head) + resized_hash[index(i.head.key, resized_hash.length)] = i end end @items = resized_hash end + + def hash_status + j = 0 + p "-------------------" + p "Load Factor: #{load_factor}" + @items.each do |i| + if i != nil + if i.instance_variable_defined?(:@next) + p i + p "Index: #{j}" + p "Key: #{i.key}" + p "Value: #{i.value}" + p "~~~~~~~~~~~~~~~~~" + j += 1 + end + if i.instance_variable_defined?(:@head) + p i + p "Index: #{j}" + p "Linked List:" + p i.print + p "~~~~~~~~~~~~~~~~~" + j += 1 + end + end + end + p "-------------------" + + end end diff --git a/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining_spec.rb b/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining_spec.rb index 4013ed2a..66a6e086 100644 --- a/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining_spec.rb +++ b/01-data-structures/05-hashes-part-2/separate_chaining/separate_chaining_spec.rb @@ -65,7 +65,7 @@ # Load factor should be .5 when two items are added expect(h.load_factor).to eq 0.5 - h["keytwo"] = "value" + h["keythree"] = "value" # Load factor goes down to .375 (3/8) since when third item is added, load factor goes to .75 # then the resize is triggered and load factor is recalculated From 4b102e19154f0200848e5e4f0fc6e0bcb38db8bc Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Mon, 15 Oct 2018 15:41:24 -0600 Subject: [PATCH 10/15] assignemnt-5 completion --- .../hashes-part-2-answers.txt | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt b/01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt index 73de2159..ae2fbf6d 100644 --- a/01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt +++ b/01-data-structures/05-hashes-part-2/hashes-part-2-answers.txt @@ -13,4 +13,44 @@ difference is that it stores the first element of each chain in the slot itself, reducing the pointer traversals by one. While it is a slight difference it could be valuable to get that extra boost of performance in certain scenarios. - A third method that wasn't in the curriculum is Hopscotch hashing. + A third method that wasn't in the curriculum is Hopscotch hashing. This method +utilizes a single array and for each slot in the array it creates a "neighborhood" +of small consecutive slots. Because of the close proximity of the "neighborhood" +the cost of finding an item with in this area is close to the cost of finding the +desired slot itself. If there isn't a spot in the "neighborhood" it uses linear +probing to find an available slot then must displace items to move this open spot +closer to the original and into the "neighborhood", which can be an expensive process. + + +Q: Create your own collision resolution strategy and describe how it works. + +A: After researching many different collision resolution strategies, and spending +a fair amount of time brain storming one of my own I came with a couple ideas. +One that incorporates separate chaining but will potentially help with the time +it takes to recall an element when a collision has taken place. My second idea +uses binary search to help with the look up when multiple keys collide with +one index. Both will utilize load factors and dynamic resizing to ensure that they +are as performant as possible. + + My first method would use linked lists and would traverse the list to find other nodes that +have collided with this index. Though I would include a counter instance variable +that would increment as the node is accessed. The linked list would be ordered by +number of times items were need, placing the most accessed item in the list at +the index and linking the second most and so on down the list. As an item is accessed +more it will be in turn be faster to access. On the fist collision in an index the second +item added will be placed at the end of the linked list, as item[i] is called its +counter would increase and if it is accessed more it will become quicker to find, thus +reducing traversals for items that have been accessed more frequently. While this +method would be harder to implement I think it could add a slight performance boost +in the right situations. + + Another method I came up with would incorporate a binary search. When a collision +occurs an array would be placed in the index location. The keys that collided +would then be placed in alphabetical order. Upon look up a binary search would run +looking for the specific key. This would be useful in hash tables that have a lot +of collisions although it would be harder to configure and set up. + + Coming up with collision resolution strategies was a difficult assignment, as +many of the most performant and space conscious methods and ideas have already been +created. While I know my methods are not perfect I enjoyed thinking about this topic +and trying to come up with some of my own. From b932822d51815ec511e4912df8a6f95523b129ef Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Tue, 16 Oct 2018 15:39:26 -0600 Subject: [PATCH 11/15] binary tree completed --- .../binary_tree/binary_search_tree.rb | 69 +++++++++++++++++++ .../06-trees/binary_tree/node.rb | 8 ++- .../min_binary_heap/min_binary_heap.rb | 40 +++++++++++ .../min_binary_heap/min_binary_heap_spec.rb | 57 +++++++++++++++ .../06-trees/min_binary_heap/node.rb | 13 ++++ .../06-trees/min_binary_heap/root.rating | 0 6 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb create mode 100644 01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb create mode 100644 01-data-structures/06-trees/min_binary_heap/node.rb create mode 100644 01-data-structures/06-trees/min_binary_heap/root.rating diff --git a/01-data-structures/06-trees/binary_tree/binary_search_tree.rb b/01-data-structures/06-trees/binary_tree/binary_search_tree.rb index 5cded8ea..f692ba3f 100644 --- a/01-data-structures/06-trees/binary_tree/binary_search_tree.rb +++ b/01-data-structures/06-trees/binary_tree/binary_search_tree.rb @@ -3,19 +3,88 @@ class BinarySearchTree def initialize(root) + @root = root + @print_queue = Queue.new + @delete_queue = Queue.new end def insert(root, node) + if node.rating < root.rating + current_node = root.left + + if current_node + insert(current_node, node) + else + root.left = node + end + + elsif node.rating > root.rating + current_node = root.right + + if current_node + insert(current_node, node) + else + root.right = node + end + + end end # Recursive Depth First Search def find(root, data) + if data.nil? + return nil + end + + if root.right != nil + current_node = root.right + elsif root.left != nil + current_node = root.left + end + + if current_node.title != data + find(current_node, data) + else + current_node + end end def delete(root, data) + if data.nil? + return nil + else + node_to_delete = find(root, data) + if node_to_delete.nil? + nil + else + node_to_delete.title = nil + node_to_delete.rating = nil + end + end end # Recursive Breadth First Search def printf(children=nil) + + if children === nil + children = @root + puts "#{children.title}: #{children.rating}" + end + + if children.left != nil + @print_queue << children.left + end + + if children.right != nil + @print_queue << children.right + end + + if @print_queue.empty? + return + else + next_val = @print_queue.pop + puts "#{next_val.title}: #{next_val.rating}" + printf(next_val) + end end end diff --git a/01-data-structures/06-trees/binary_tree/node.rb b/01-data-structures/06-trees/binary_tree/node.rb index c0106c8c..2de6111f 100644 --- a/01-data-structures/06-trees/binary_tree/node.rb +++ b/01-data-structures/06-trees/binary_tree/node.rb @@ -5,5 +5,9 @@ class Node attr_accessor :right def initialize(title, rating) - end -end \ No newline at end of file + @title = title + @rating = rating + @right = nil + @left = nil + end +end diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb new file mode 100644 index 00000000..7879154a --- /dev/null +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb @@ -0,0 +1,40 @@ +require_relative 'node' + +class MinBinaryHeap + + def initialize(root) + @root = root + end + + def insert(root, data) + if data.rating < root.rating + + if current_node + insert(current_node, node) + else + root.left = node + end + + # elsif node.rating > root.rating + # current_node = root.right + # + # if current_node + # insert(current_node, node) + # else + # root.right = node + # end + + end + end + + def delete(root, data) + end + + def find(root, data) + end + + def print(root) + end + + +end diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb new file mode 100644 index 00000000..557f8712 --- /dev/null +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb @@ -0,0 +1,57 @@ +include RSpec + +require_relative 'min_binary_heap' + +RSpec.describe MinBinaryHeap, type: Class do + let (:root) { Node.new("The Matrix", 87) } + + let (:heap) { MinBinaryHeap.new(root) } + let (:pacific_rim) { Node.new("Pacific Rim", 72) } + let (:braveheart) { Node.new("Braveheart", 78) } + let (:jedi) { Node.new("Star Wars: Return of the Jedi", 80) } + let (:donnie) { Node.new("Donnie Darko", 85) } + let (:inception) { Node.new("Inception", 86) } + let (:district) { Node.new("District 9", 90) } + let (:shawshank) { Node.new("The Shawshank Redemption", 91) } + let (:martian) { Node.new("The Martian", 92) } + let (:hope) { Node.new("Star Wars: A New Hope", 93) } + let (:empire) { Node.new("Star Wars: The Empire Strikes Back", 94) } + let (:mad_max_2) { Node.new("Mad Max 2: The Road Warrior", 98) } + + describe "#insert(data)" do + it "properly inserts a new node as a left child" do + heap.insert(root, pacific_rim) + expect(root.left.title).to eq "Pacific Rim" + end + + # it "properly inserts a new node as a left-left child" do + # heap.insert(root, braveheart) + # heap.insert(root, pacific_rim) + # expect(root.left.left.title).to eq "Pacific Rim" + # end + # + # it "properly inserts a new node as a left-right child" do + # heap.insert(root, donnie) + # heap.insert(root, inception) + # expect(root.left.right.title).to eq "Inception" + # end + # + # it "properly inserts a new node as a right child" do + # heap.insert(root, district) + # expect(root.right.title).to eq "District 9" + # end + # + # it "properly inserts a new node as a right-left child" do + # heap.insert(root, hope) + # heap.insert(root, martian) + # expect(root.right.left.title).to eq "The Martian" + # end + # + # it "properly inserts a new node as a right-right child" do + # heap.insert(root, empire) + # heap.insert(root, mad_max_2) + # expect(root.right.right.title).to eq "Mad Max 2: The Road Warrior" + # end + end + +end diff --git a/01-data-structures/06-trees/min_binary_heap/node.rb b/01-data-structures/06-trees/min_binary_heap/node.rb new file mode 100644 index 00000000..d008bce5 --- /dev/null +++ b/01-data-structures/06-trees/min_binary_heap/node.rb @@ -0,0 +1,13 @@ +class Node + attr_accessor :title + attr_accessor :rating + attr_accessor :left + attr_accessor :right + + def initialize(title, rating) + @title = title + @rating = rating + @right = nil + @left = nil + end +end diff --git a/01-data-structures/06-trees/min_binary_heap/root.rating b/01-data-structures/06-trees/min_binary_heap/root.rating new file mode 100644 index 00000000..e69de29b From 549160c7da6a9d23412f373be2c97107ead8098a Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Tue, 16 Oct 2018 16:18:22 -0600 Subject: [PATCH 12/15] min heap completion --- .../binary_tree/binary_search_tree.rb | 1 - .../min_binary_heap/min_binary_heap.rb | 71 +++++-- .../min_binary_heap/min_binary_heap_spec.rb | 175 +++++++++++++++--- .../06-trees/min_binary_heap/root.rating | 0 4 files changed, 206 insertions(+), 41 deletions(-) delete mode 100644 01-data-structures/06-trees/min_binary_heap/root.rating diff --git a/01-data-structures/06-trees/binary_tree/binary_search_tree.rb b/01-data-structures/06-trees/binary_tree/binary_search_tree.rb index f692ba3f..94e30f8b 100644 --- a/01-data-structures/06-trees/binary_tree/binary_search_tree.rb +++ b/01-data-structures/06-trees/binary_tree/binary_search_tree.rb @@ -5,7 +5,6 @@ class BinarySearchTree def initialize(root) @root = root @print_queue = Queue.new - @delete_queue = Queue.new end def insert(root, node) diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb index 7879154a..5b02511e 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb @@ -4,36 +4,83 @@ class MinBinaryHeap def initialize(root) @root = root + @print_queue = Queue.new end def insert(root, data) if data.rating < root.rating + current_node = root.left if current_node - insert(current_node, node) + insert(current_node, data) else - root.left = node + root.left = data end + elsif data.rating > root.rating + current_node = root.right - # elsif node.rating > root.rating - # current_node = root.right - # - # if current_node - # insert(current_node, node) - # else - # root.right = node - # end - + if current_node + insert(current_node, data) + else + root.right = data + end end + end def delete(root, data) + if data.nil? + return nil + else + node_to_delete = find(root, data) + if node_to_delete.nil? + nil + else + node_to_delete.title = nil + node_to_delete.rating = nil + end + end end def find(root, data) + if data.nil? + return nil + end + + if root.right != nil + current_node = root.right + elsif root.left != nil + current_node = root.left + end + + if current_node.title != data + find(current_node, data) + else + current_node + end end - def print(root) + def print(root=nil) + if root === nil + root = @root + puts "#{root.title}: #{root.rating}" + end + + if root.left != nil + @print_queue << root.left + end + + if root.right != nil + @print_queue << root.right + end + + if @print_queue.empty? + return + else + next_val = @print_queue.pop + puts "#{next_val.title}: #{next_val.rating}" + print(next_val) + end end diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb index 557f8712..1e2454c7 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb @@ -24,34 +24,153 @@ expect(root.left.title).to eq "Pacific Rim" end - # it "properly inserts a new node as a left-left child" do - # heap.insert(root, braveheart) - # heap.insert(root, pacific_rim) - # expect(root.left.left.title).to eq "Pacific Rim" - # end - # - # it "properly inserts a new node as a left-right child" do - # heap.insert(root, donnie) - # heap.insert(root, inception) - # expect(root.left.right.title).to eq "Inception" - # end - # - # it "properly inserts a new node as a right child" do - # heap.insert(root, district) - # expect(root.right.title).to eq "District 9" - # end - # - # it "properly inserts a new node as a right-left child" do - # heap.insert(root, hope) - # heap.insert(root, martian) - # expect(root.right.left.title).to eq "The Martian" - # end - # - # it "properly inserts a new node as a right-right child" do - # heap.insert(root, empire) - # heap.insert(root, mad_max_2) - # expect(root.right.right.title).to eq "Mad Max 2: The Road Warrior" - # end + it "properly inserts a new node as a left-left child" do + heap.insert(root, braveheart) + heap.insert(root, pacific_rim) + expect(root.left.left.title).to eq "Pacific Rim" + end + + it "properly inserts a new node as a left-right child" do + heap.insert(root, donnie) + heap.insert(root, inception) + expect(root.left.right.title).to eq "Inception" + end + + it "properly inserts a new node as a right child" do + heap.insert(root, district) + expect(root.right.title).to eq "District 9" + end + + it "properly inserts a new node as a right-left child" do + heap.insert(root, hope) + heap.insert(root, martian) + expect(root.right.left.title).to eq "The Martian" + end + + it "properly inserts a new node as a right-right child" do + heap.insert(root, empire) + heap.insert(root, mad_max_2) + expect(root.right.right.title).to eq "Mad Max 2: The Road Warrior" + end end + describe "#find(data)" do + it "handles nil gracefully" do + heap.insert(root, empire) + heap.insert(root, mad_max_2) + expect(heap.find(root, nil)).to eq nil + end + + it "properly finds a left node" do + heap.insert(root, pacific_rim) + expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" + end + + it "properly finds a left-left node" do + heap.insert(root, braveheart) + heap.insert(root, pacific_rim) + expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" + end + + it "properly finds a left-right node" do + heap.insert(root, donnie) + heap.insert(root, inception) + expect(heap.find(root, inception.title).title).to eq "Inception" + end + + it "properly finds a right node" do + heap.insert(root, district) + expect(heap.find(root, district.title).title).to eq "District 9" + end + + it "properly finds a right-left node" do + heap.insert(root, hope) + heap.insert(root, martian) + expect(heap.find(root, martian.title).title).to eq "The Martian" + end + + it "properly finds a right-right node" do + heap.insert(root, empire) + heap.insert(root, mad_max_2) + expect(heap.find(root, mad_max_2.title).title).to eq "Mad Max 2: The Road Warrior" + end + end + + describe "#delete(data)" do + it "handles nil gracefully" do + expect(heap.delete(root, nil)).to eq nil + end + + it "properly deletes a left node" do + heap.insert(root, hope) + heap.delete(root, hope.title) + expect(heap.find(root, hope.title)).to be_nil + end + + it "properly deletes a left-left node" do + heap.insert(root, braveheart) + heap.insert(root, pacific_rim) + heap.delete(root, pacific_rim.title) + expect(heap.find(root, pacific_rim.title)).to be_nil + end + + it "properly deletes a left-right node" do + heap.insert(root, donnie) + heap.insert(root, inception) + heap.delete(root, inception.title) + expect(heap.find(root, inception.title)).to be_nil + end + + it "properly deletes a right node" do + heap.insert(root, district) + heap.delete(root, district.title) + expect(heap.find(root, district.title)).to be_nil + end + + it "properly deletes a right-left node" do + heap.insert(root, hope) + heap.insert(root, martian) + heap.delete(root, martian.title) + expect(heap.find(root, martian.title)).to be_nil + end + + it "properly deletes a right-right node" do + heap.insert(root, empire) + heap.insert(root, mad_max_2) + heap.delete(root, mad_max_2.title) + expect(heap.find(root, mad_max_2.title)).to be_nil + end + end + + describe "#print" do + specify { + expected_output = "The Matrix: 87\nStar Wars: Return of the Jedi: 80\nStar Wars: A New Hope: 93\nPacific Rim: 72\nInception: 86\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nBraveheart: 78\nThe Shawshank Redemption: 91\nMad Max 2: The Road Warrior: 98\nDistrict 9: 90\n" + heap.insert(root, hope) + heap.insert(root, empire) + heap.insert(root, jedi) + heap.insert(root, martian) + heap.insert(root, pacific_rim) + heap.insert(root, inception) + heap.insert(root, braveheart) + heap.insert(root, shawshank) + heap.insert(root, district) + heap.insert(root, mad_max_2) + expect { heap.print }.to output(expected_output).to_stdout + } + + specify { + expected_output = "The Matrix: 87\nBraveheart: 78\nMad Max 2: The Road Warrior: 98\nPacific Rim: 72\nInception: 86\nDistrict 9: 90\nStar Wars: Return of the Jedi: 80\nThe Shawshank Redemption: 91\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nStar Wars: A New Hope: 93\n" + heap.insert(root, mad_max_2) + heap.insert(root, district) + heap.insert(root, shawshank) + heap.insert(root, braveheart) + heap.insert(root, inception) + heap.insert(root, pacific_rim) + heap.insert(root, martian) + heap.insert(root, jedi) + heap.insert(root, empire) + heap.insert(root, hope) + expect { heap.print }.to output(expected_output).to_stdout + } + end end diff --git a/01-data-structures/06-trees/min_binary_heap/root.rating b/01-data-structures/06-trees/min_binary_heap/root.rating deleted file mode 100644 index e69de29b..00000000 From 6ec786b17882ce7892e23b6a0d6497ab23cba3b6 Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Tue, 16 Oct 2018 17:48:06 -0600 Subject: [PATCH 13/15] heap spec work --- .../min_binary_heap/min_binary_heap.rb | 26 +- .../min_binary_heap/min_binary_heap_spec.rb | 310 +++++++++--------- 2 files changed, 177 insertions(+), 159 deletions(-) diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb index 5b02511e..fc9cf53a 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb @@ -2,28 +2,38 @@ class MinBinaryHeap + attr_accessor :root + def initialize(root) @root = root @print_queue = Queue.new end def insert(root, data) - if data.rating < root.rating - current_node = root.left + if data.rating < @root.rating + temp = @root + @root = data + p @root + insert(@root, temp) - if current_node - insert(current_node, data) - else - root.left = data - end elsif data.rating > root.rating current_node = root.right - if current_node + if current_node && root.left != nil insert(current_node, data) + elsif root.left == nil && root.right != nil + root.left = data else root.right = data end + # elsif data.rating > root.rating + # current_node = root.right + # + # if current_node + # insert(current_node, data) + # else + # root.right = data + # end end end diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb index 1e2454c7..d4ff8ee5 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb @@ -3,9 +3,9 @@ require_relative 'min_binary_heap' RSpec.describe MinBinaryHeap, type: Class do - let (:root) { Node.new("The Matrix", 87) } + let (:root_start) { Node.new("The Matrix", 87) } - let (:heap) { MinBinaryHeap.new(root) } + let (:heap) { MinBinaryHeap.new(root_start) } let (:pacific_rim) { Node.new("Pacific Rim", 72) } let (:braveheart) { Node.new("Braveheart", 78) } let (:jedi) { Node.new("Star Wars: Return of the Jedi", 80) } @@ -19,158 +19,166 @@ let (:mad_max_2) { Node.new("Mad Max 2: The Road Warrior", 98) } describe "#insert(data)" do - it "properly inserts a new node as a left child" do - heap.insert(root, pacific_rim) - expect(root.left.title).to eq "Pacific Rim" - end - - it "properly inserts a new node as a left-left child" do - heap.insert(root, braveheart) - heap.insert(root, pacific_rim) - expect(root.left.left.title).to eq "Pacific Rim" - end + # it "replaces root if insert is less then @root" do + # heap.insert(root_start, pacific_rim) + # expect(MinBinaryHeap.instance_variable_get(:@root)).to eq pacific_rim + # end - it "properly inserts a new node as a left-right child" do - heap.insert(root, donnie) - heap.insert(root, inception) - expect(root.left.right.title).to eq "Inception" - end + it "properly inserts a new node as a left child" do + heap.insert(root_start, district) + heap.insert(root_start, empire) + expect(root_start.left.title).to eq "Star Wars: The Empire Strikes Back" + end + + # it "properly inserts a new node as a left-left child" do + # heap.insert(root_start, district) + # heap.insert(root_start, shawshank) + # heap.insert(root_start, martian) + # heap.insert(root_start, hope) + # expect(root_start.left.left.title).to eq "Star Wars: A New Hope" + # end + # + # it "properly inserts a new node as a left-right child" do + # heap.insert(root, donnie) + # heap.insert(root, inception) + # expect(root.left.right.title).to eq "Inception" + # end it "properly inserts a new node as a right child" do - heap.insert(root, district) - expect(root.right.title).to eq "District 9" - end - - it "properly inserts a new node as a right-left child" do - heap.insert(root, hope) - heap.insert(root, martian) - expect(root.right.left.title).to eq "The Martian" - end - - it "properly inserts a new node as a right-right child" do - heap.insert(root, empire) - heap.insert(root, mad_max_2) - expect(root.right.right.title).to eq "Mad Max 2: The Road Warrior" - end + heap.insert(root_start, district) + expect(root_start.right.title).to eq "District 9" + end + + # it "properly inserts a new node as a right-left child" do + # heap.insert(root, hope) + # heap.insert(root, martian) + # expect(root.right.left.title).to eq "The Martian" + # end + # + # it "properly inserts a new node as a right-right child" do + # heap.insert(root, empire) + # heap.insert(root, mad_max_2) + # expect(root.right.right.title).to eq "Mad Max 2: The Road Warrior" + # end end - describe "#find(data)" do - it "handles nil gracefully" do - heap.insert(root, empire) - heap.insert(root, mad_max_2) - expect(heap.find(root, nil)).to eq nil - end - - it "properly finds a left node" do - heap.insert(root, pacific_rim) - expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" - end - - it "properly finds a left-left node" do - heap.insert(root, braveheart) - heap.insert(root, pacific_rim) - expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" - end - - it "properly finds a left-right node" do - heap.insert(root, donnie) - heap.insert(root, inception) - expect(heap.find(root, inception.title).title).to eq "Inception" - end - - it "properly finds a right node" do - heap.insert(root, district) - expect(heap.find(root, district.title).title).to eq "District 9" - end - - it "properly finds a right-left node" do - heap.insert(root, hope) - heap.insert(root, martian) - expect(heap.find(root, martian.title).title).to eq "The Martian" - end - - it "properly finds a right-right node" do - heap.insert(root, empire) - heap.insert(root, mad_max_2) - expect(heap.find(root, mad_max_2.title).title).to eq "Mad Max 2: The Road Warrior" - end - end - - describe "#delete(data)" do - it "handles nil gracefully" do - expect(heap.delete(root, nil)).to eq nil - end - - it "properly deletes a left node" do - heap.insert(root, hope) - heap.delete(root, hope.title) - expect(heap.find(root, hope.title)).to be_nil - end - - it "properly deletes a left-left node" do - heap.insert(root, braveheart) - heap.insert(root, pacific_rim) - heap.delete(root, pacific_rim.title) - expect(heap.find(root, pacific_rim.title)).to be_nil - end - - it "properly deletes a left-right node" do - heap.insert(root, donnie) - heap.insert(root, inception) - heap.delete(root, inception.title) - expect(heap.find(root, inception.title)).to be_nil - end - - it "properly deletes a right node" do - heap.insert(root, district) - heap.delete(root, district.title) - expect(heap.find(root, district.title)).to be_nil - end - - it "properly deletes a right-left node" do - heap.insert(root, hope) - heap.insert(root, martian) - heap.delete(root, martian.title) - expect(heap.find(root, martian.title)).to be_nil - end - - it "properly deletes a right-right node" do - heap.insert(root, empire) - heap.insert(root, mad_max_2) - heap.delete(root, mad_max_2.title) - expect(heap.find(root, mad_max_2.title)).to be_nil - end - end - - describe "#print" do - specify { - expected_output = "The Matrix: 87\nStar Wars: Return of the Jedi: 80\nStar Wars: A New Hope: 93\nPacific Rim: 72\nInception: 86\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nBraveheart: 78\nThe Shawshank Redemption: 91\nMad Max 2: The Road Warrior: 98\nDistrict 9: 90\n" - heap.insert(root, hope) - heap.insert(root, empire) - heap.insert(root, jedi) - heap.insert(root, martian) - heap.insert(root, pacific_rim) - heap.insert(root, inception) - heap.insert(root, braveheart) - heap.insert(root, shawshank) - heap.insert(root, district) - heap.insert(root, mad_max_2) - expect { heap.print }.to output(expected_output).to_stdout - } - - specify { - expected_output = "The Matrix: 87\nBraveheart: 78\nMad Max 2: The Road Warrior: 98\nPacific Rim: 72\nInception: 86\nDistrict 9: 90\nStar Wars: Return of the Jedi: 80\nThe Shawshank Redemption: 91\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nStar Wars: A New Hope: 93\n" - heap.insert(root, mad_max_2) - heap.insert(root, district) - heap.insert(root, shawshank) - heap.insert(root, braveheart) - heap.insert(root, inception) - heap.insert(root, pacific_rim) - heap.insert(root, martian) - heap.insert(root, jedi) - heap.insert(root, empire) - heap.insert(root, hope) - expect { heap.print }.to output(expected_output).to_stdout - } - end + # describe "#find(data)" do + # it "handles nil gracefully" do + # heap.insert(root, empire) + # heap.insert(root, mad_max_2) + # expect(heap.find(root, nil)).to eq nil + # end + # + # it "properly finds a left node" do + # heap.insert(root, pacific_rim) + # expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" + # end + # + # it "properly finds a left-left node" do + # heap.insert(root, braveheart) + # heap.insert(root, pacific_rim) + # expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" + # end + # + # it "properly finds a left-right node" do + # heap.insert(root, donnie) + # heap.insert(root, inception) + # expect(heap.find(root, inception.title).title).to eq "Inception" + # end + # + # it "properly finds a right node" do + # heap.insert(root, district) + # expect(heap.find(root, district.title).title).to eq "District 9" + # end + # + # it "properly finds a right-left node" do + # heap.insert(root, hope) + # heap.insert(root, martian) + # expect(heap.find(root, martian.title).title).to eq "The Martian" + # end + # + # it "properly finds a right-right node" do + # heap.insert(root, empire) + # heap.insert(root, mad_max_2) + # expect(heap.find(root, mad_max_2.title).title).to eq "Mad Max 2: The Road Warrior" + # end + # end + # + # describe "#delete(data)" do + # it "handles nil gracefully" do + # expect(heap.delete(root, nil)).to eq nil + # end + # + # it "properly deletes a left node" do + # heap.insert(root, hope) + # heap.delete(root, hope.title) + # expect(heap.find(root, hope.title)).to be_nil + # end + # + # it "properly deletes a left-left node" do + # heap.insert(root, braveheart) + # heap.insert(root, pacific_rim) + # heap.delete(root, pacific_rim.title) + # expect(heap.find(root, pacific_rim.title)).to be_nil + # end + # + # it "properly deletes a left-right node" do + # heap.insert(root, donnie) + # heap.insert(root, inception) + # heap.delete(root, inception.title) + # expect(heap.find(root, inception.title)).to be_nil + # end + # + # it "properly deletes a right node" do + # heap.insert(root, district) + # heap.delete(root, district.title) + # expect(heap.find(root, district.title)).to be_nil + # end + # + # it "properly deletes a right-left node" do + # heap.insert(root, hope) + # heap.insert(root, martian) + # heap.delete(root, martian.title) + # expect(heap.find(root, martian.title)).to be_nil + # end + # + # it "properly deletes a right-right node" do + # heap.insert(root, empire) + # heap.insert(root, mad_max_2) + # heap.delete(root, mad_max_2.title) + # expect(heap.find(root, mad_max_2.title)).to be_nil + # end + # end + # + # describe "#print" do + # specify { + # expected_output = "The Matrix: 87\nStar Wars: Return of the Jedi: 80\nStar Wars: A New Hope: 93\nPacific Rim: 72\nInception: 86\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nBraveheart: 78\nThe Shawshank Redemption: 91\nMad Max 2: The Road Warrior: 98\nDistrict 9: 90\n" + # heap.insert(root, hope) + # heap.insert(root, empire) + # heap.insert(root, jedi) + # heap.insert(root, martian) + # heap.insert(root, pacific_rim) + # heap.insert(root, inception) + # heap.insert(root, braveheart) + # heap.insert(root, shawshank) + # heap.insert(root, district) + # heap.insert(root, mad_max_2) + # expect { heap.print }.to output(expected_output).to_stdout + # } + # + # specify { + # expected_output = "The Matrix: 87\nBraveheart: 78\nMad Max 2: The Road Warrior: 98\nPacific Rim: 72\nInception: 86\nDistrict 9: 90\nStar Wars: Return of the Jedi: 80\nThe Shawshank Redemption: 91\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nStar Wars: A New Hope: 93\n" + # heap.insert(root, mad_max_2) + # heap.insert(root, district) + # heap.insert(root, shawshank) + # heap.insert(root, braveheart) + # heap.insert(root, inception) + # heap.insert(root, pacific_rim) + # heap.insert(root, martian) + # heap.insert(root, jedi) + # heap.insert(root, empire) + # heap.insert(root, hope) + # expect { heap.print }.to output(expected_output).to_stdout + # } + # end end From b619f26c53a506737141b3c98997628d51246a98 Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Wed, 17 Oct 2018 19:51:43 -0600 Subject: [PATCH 14/15] assignment-6 work --- .../min_binary_heap/min_binary_heap.rb | 47 +++---- .../min_binary_heap/min_binary_heap_spec.rb | 129 ++++++++++-------- .../06-trees/min_binary_heap/root.rating | 0 3 files changed, 88 insertions(+), 88 deletions(-) create mode 100644 01-data-structures/06-trees/min_binary_heap/root.rating diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb index fc9cf53a..d4f03ded 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb @@ -10,30 +10,23 @@ def initialize(root) end def insert(root, data) - if data.rating < @root.rating - temp = @root - @root = data - p @root - insert(@root, temp) + if data.rating < root.rating + puts "jeool" + temp = root + root = data + insert(data, temp) elsif data.rating > root.rating - current_node = root.right - if current_node && root.left != nil - insert(current_node, data) - elsif root.left == nil && root.right != nil + if root.left == nil root.left = data - else + elsif root.right == nil root.right = data + elsif root.left.left == nil || root.left.right == nil + insert(root.left, data) + elsif root.right.right == nil || root.right.left == nil + insert(root.right, data) end - # elsif data.rating > root.rating - # current_node = root.right - # - # if current_node - # insert(current_node, data) - # else - # root.right = data - # end end end @@ -55,18 +48,14 @@ def delete(root, data) def find(root, data) if data.nil? return nil - end - - if root.right != nil - current_node = root.right - elsif root.left != nil - current_node = root.left - end - - if current_node.title != data - find(current_node, data) else - current_node + if root.title == data + return root + elsif root.left != nil + find(root.left, data) + elsif root.right != nil + find(root.right, data) + end end end diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb index d4ff8ee5..8de3dc8e 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb @@ -10,7 +10,7 @@ let (:braveheart) { Node.new("Braveheart", 78) } let (:jedi) { Node.new("Star Wars: Return of the Jedi", 80) } let (:donnie) { Node.new("Donnie Darko", 85) } - let (:inception) { Node.new("Inception", 86) } + let (:inception) { Node.new("Inception", 96) } let (:district) { Node.new("District 9", 90) } let (:shawshank) { Node.new("The Shawshank Redemption", 91) } let (:martian) { Node.new("The Martian", 92) } @@ -19,61 +19,71 @@ let (:mad_max_2) { Node.new("Mad Max 2: The Road Warrior", 98) } describe "#insert(data)" do - # it "replaces root if insert is less then @root" do - # heap.insert(root_start, pacific_rim) - # expect(MinBinaryHeap.instance_variable_get(:@root)).to eq pacific_rim - # end - it "properly inserts a new node as a left child" do heap.insert(root_start, district) - heap.insert(root_start, empire) - expect(root_start.left.title).to eq "Star Wars: The Empire Strikes Back" + expect(root_start.left.title).to eq "District 9" end - # it "properly inserts a new node as a left-left child" do - # heap.insert(root_start, district) - # heap.insert(root_start, shawshank) + # it "properly swaps when value is less then" do # heap.insert(root_start, martian) - # heap.insert(root_start, hope) - # expect(root_start.left.left.title).to eq "Star Wars: A New Hope" - # end - # - # it "properly inserts a new node as a left-right child" do - # heap.insert(root, donnie) - # heap.insert(root, inception) - # expect(root.left.right.title).to eq "Inception" + # heap.insert(root_start, empire) + # heap.insert(root_start, district) + # expect(root_start.left.title).to eq "District 9" # end + it "properly inserts a new node as a left-left child" do + heap.insert(root_start, district) + heap.insert(root_start, empire) + heap.insert(root_start, martian) + expect(root_start.left.left.title).to eq "The Martian" + end + + it "properly inserts a new node as a left-right child" do + heap.insert(root_start, district) + heap.insert(root_start, empire) + heap.insert(root_start, martian) + heap.insert(root_start, hope) + expect(root_start.left.right.title).to eq "Star Wars: A New Hope" + end + it "properly inserts a new node as a right child" do heap.insert(root_start, district) - expect(root_start.right.title).to eq "District 9" + heap.insert(root_start, empire) + expect(root_start.right.title).to eq "Star Wars: The Empire Strikes Back" end - # it "properly inserts a new node as a right-left child" do - # heap.insert(root, hope) - # heap.insert(root, martian) - # expect(root.right.left.title).to eq "The Martian" - # end - # - # it "properly inserts a new node as a right-right child" do - # heap.insert(root, empire) - # heap.insert(root, mad_max_2) - # expect(root.right.right.title).to eq "Mad Max 2: The Road Warrior" - # end + it "properly inserts a new node as a right-left child" do + heap.insert(root_start, district) + heap.insert(root_start, empire) + heap.insert(root_start, martian) + heap.insert(root_start, hope) + heap.insert(root_start, mad_max_2) + expect(root_start.right.left.title).to eq "Mad Max 2: The Road Warrior" + end + + it "properly inserts a new node as a right-right child" do + heap.insert(root_start, district) + heap.insert(root_start, empire) + heap.insert(root_start, martian) + heap.insert(root_start, hope) + heap.insert(root_start, mad_max_2) + heap.insert(root_start, inception) + expect(root_start.right.right.title).to eq "Inception" + end end - # describe "#find(data)" do - # it "handles nil gracefully" do - # heap.insert(root, empire) - # heap.insert(root, mad_max_2) - # expect(heap.find(root, nil)).to eq nil - # end - # - # it "properly finds a left node" do - # heap.insert(root, pacific_rim) - # expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" - # end - # + describe "#find(data)" do + it "handles nil gracefully" do + heap.insert(root_start, empire) + heap.insert(root_start, mad_max_2) + expect(heap.find(root_start, nil)).to eq nil + end + + it "properly finds a left node" do + heap.insert(root_start, district) + expect(heap.find(root_start, district.title).title).to eq "District 9" + end + # it "properly finds a left-left node" do # heap.insert(root, braveheart) # heap.insert(root, pacific_rim) @@ -86,10 +96,11 @@ # expect(heap.find(root, inception.title).title).to eq "Inception" # end # - # it "properly finds a right node" do - # heap.insert(root, district) - # expect(heap.find(root, district.title).title).to eq "District 9" - # end + # it "properly finds a right node" do + # heap.insert(root_start, district) + # heap.insert(root_start, empire) + # expect(heap.find(root_start, empire.title).title).to eq "Star Wars: The Empire Strikes Back" + # end # # it "properly finds a right-left node" do # heap.insert(root, hope) @@ -102,18 +113,18 @@ # heap.insert(root, mad_max_2) # expect(heap.find(root, mad_max_2.title).title).to eq "Mad Max 2: The Road Warrior" # end - # end - # - # describe "#delete(data)" do - # it "handles nil gracefully" do - # expect(heap.delete(root, nil)).to eq nil - # end + end # - # it "properly deletes a left node" do - # heap.insert(root, hope) - # heap.delete(root, hope.title) - # expect(heap.find(root, hope.title)).to be_nil - # end + describe "#delete(data)" do + it "handles nil gracefully" do + expect(heap.delete(root_start, nil)).to eq nil + end + + it "properly deletes a left node" do + heap.insert(root_start, district) + heap.delete(root_start, district.title) + expect(heap.find(root_start, district.title)).to be_nil + end # # it "properly deletes a left-left node" do # heap.insert(root, braveheart) @@ -148,7 +159,7 @@ # heap.delete(root, mad_max_2.title) # expect(heap.find(root, mad_max_2.title)).to be_nil # end - # end + end # # describe "#print" do # specify { diff --git a/01-data-structures/06-trees/min_binary_heap/root.rating b/01-data-structures/06-trees/min_binary_heap/root.rating new file mode 100644 index 00000000..e69de29b From 5b924513e954b41e1e58c5107dca5cbbdadea16f Mon Sep 17 00:00:00 2001 From: Conor Souhrada Date: Mon, 22 Oct 2018 18:36:59 -0600 Subject: [PATCH 15/15] assignment-6 completion --- .../min_binary_heap/min_binary_heap.rb | 94 ++---- .../min_binary_heap/min_binary_heap_spec.rb | 307 ++++++++++-------- .../06-trees/min_binary_heap/node.rb | 4 - 01-data-structures/06-trees/tree-answers.txt | 58 ++++ 4 files changed, 255 insertions(+), 208 deletions(-) diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb index d4f03ded..e61b63a8 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap.rb @@ -1,86 +1,60 @@ require_relative 'node' -class MinBinaryHeap +class MinHeap - attr_accessor :root +attr_accessor :root, :heap def initialize(root) @root = root - @print_queue = Queue.new + @heap = Array.new(1, @root) end - def insert(root, data) - if data.rating < root.rating - puts "jeool" - temp = root - root = data - insert(data, temp) - - elsif data.rating > root.rating + def insert(data) + @heap << data + heap_up + end - if root.left == nil - root.left = data - elsif root.right == nil - root.right = data - elsif root.left.left == nil || root.left.right == nil - insert(root.left, data) - elsif root.right.right == nil || root.right.left == nil - insert(root.right, data) - end + def heap_up + index = @heap.length - 1 + parent = ((index - 2.to_f) / 2).ceil + while @heap[parent] && parent >= 0 && @heap[parent].rating > @heap[index].rating + swap(parent, index) + index = parent + parent = ((index - 2.to_f) / 2).ceil end + end + def swap(index_one, index_two) + temp = @heap[index_one] + @heap[index_one] = @heap[index_two] + @heap[index_two] = temp end - def delete(root, data) - if data.nil? - return nil - else - node_to_delete = find(root, data) - if node_to_delete.nil? - nil + def find(data) + i = 0 + while i < @heap.length + if(@heap[i].title == data) + return @heap[i] + i = @heap.length else - node_to_delete.title = nil - node_to_delete.rating = nil + i += 1 end end end - def find(root, data) - if data.nil? - return nil + def delete(data) + if(data == @heap.last.title) + @heap.pop() else - if root.title == data - return root - elsif root.left != nil - find(root.left, data) - elsif root.right != nil - find(root.right, data) - end + item_delete = find(data) + @heap.delete(item_delete) end end - def print(root=nil) - if root === nil - root = @root - puts "#{root.title}: #{root.rating}" - end - - if root.left != nil - @print_queue << root.left - end - - if root.right != nil - @print_queue << root.right - end - - if @print_queue.empty? - return - else - next_val = @print_queue.pop - puts "#{next_val.title}: #{next_val.rating}" - print(next_val) + def printf + @heap.each do |item| + puts "#{item.title}: #{item.rating}" end end - end diff --git a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb index 8de3dc8e..2a6362f5 100644 --- a/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb +++ b/01-data-structures/06-trees/min_binary_heap/min_binary_heap_spec.rb @@ -2,10 +2,10 @@ require_relative 'min_binary_heap' -RSpec.describe MinBinaryHeap, type: Class do +RSpec.describe MinHeap, type: Class do let (:root_start) { Node.new("The Matrix", 87) } - let (:heap) { MinBinaryHeap.new(root_start) } + let (:heap) { MinHeap.new(root_start) } let (:pacific_rim) { Node.new("Pacific Rim", 72) } let (:braveheart) { Node.new("Braveheart", 78) } let (:jedi) { Node.new("Star Wars: Return of the Jedi", 80) } @@ -19,177 +19,196 @@ let (:mad_max_2) { Node.new("Mad Max 2: The Road Warrior", 98) } describe "#insert(data)" do - it "properly inserts a new node as a left child" do - heap.insert(root_start, district) - expect(root_start.left.title).to eq "District 9" + it "swaps root if insert is smaller then root" do + heap.insert(pacific_rim) + expect(heap.heap[0].title).to eq "Pacific Rim" end - # it "properly swaps when value is less then" do - # heap.insert(root_start, martian) - # heap.insert(root_start, empire) - # heap.insert(root_start, district) - # expect(root_start.left.title).to eq "District 9" - # end + it "properly inserts a new node as a left child" do + heap.insert(district) + expect(heap.heap[1].title).to eq "District 9" + end it "properly inserts a new node as a left-left child" do - heap.insert(root_start, district) - heap.insert(root_start, empire) - heap.insert(root_start, martian) - expect(root_start.left.left.title).to eq "The Martian" + heap.insert(pacific_rim) + heap.insert(district) + heap.insert(donnie) + expect(heap.heap[3].title).to eq "The Matrix" end it "properly inserts a new node as a left-right child" do - heap.insert(root_start, district) - heap.insert(root_start, empire) - heap.insert(root_start, martian) - heap.insert(root_start, hope) - expect(root_start.left.right.title).to eq "Star Wars: A New Hope" + heap.insert(pacific_rim) + heap.insert(district) + heap.insert(donnie) + heap.insert(empire) + expect(heap.heap[4].title).to eq "Star Wars: The Empire Strikes Back" end it "properly inserts a new node as a right child" do - heap.insert(root_start, district) - heap.insert(root_start, empire) - expect(root_start.right.title).to eq "Star Wars: The Empire Strikes Back" + heap.insert(district) + heap.insert(empire) + expect(heap.heap[2].title).to eq "Star Wars: The Empire Strikes Back" end it "properly inserts a new node as a right-left child" do - heap.insert(root_start, district) - heap.insert(root_start, empire) - heap.insert(root_start, martian) - heap.insert(root_start, hope) - heap.insert(root_start, mad_max_2) - expect(root_start.right.left.title).to eq "Mad Max 2: The Road Warrior" + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + heap.insert(hope) + heap.insert(mad_max_2) + expect(heap.heap[5].title).to eq "Mad Max 2: The Road Warrior" end it "properly inserts a new node as a right-right child" do - heap.insert(root_start, district) - heap.insert(root_start, empire) - heap.insert(root_start, martian) - heap.insert(root_start, hope) - heap.insert(root_start, mad_max_2) - heap.insert(root_start, inception) - expect(root_start.right.right.title).to eq "Inception" + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + heap.insert(hope) + heap.insert(mad_max_2) + heap.insert(inception) + expect(heap.heap[6].title).to eq "Inception" end end describe "#find(data)" do it "handles nil gracefully" do - heap.insert(root_start, empire) - heap.insert(root_start, mad_max_2) - expect(heap.find(root_start, nil)).to eq nil + heap.insert(empire) + heap.insert(mad_max_2) + expect(heap.find(nil)).to eq nil end it "properly finds a left node" do - heap.insert(root_start, district) - expect(heap.find(root_start, district.title).title).to eq "District 9" - end - - # it "properly finds a left-left node" do - # heap.insert(root, braveheart) - # heap.insert(root, pacific_rim) - # expect(heap.find(root, pacific_rim.title).title).to eq "Pacific Rim" - # end - # - # it "properly finds a left-right node" do - # heap.insert(root, donnie) - # heap.insert(root, inception) - # expect(heap.find(root, inception.title).title).to eq "Inception" - # end - # - # it "properly finds a right node" do - # heap.insert(root_start, district) - # heap.insert(root_start, empire) - # expect(heap.find(root_start, empire.title).title).to eq "Star Wars: The Empire Strikes Back" - # end - # - # it "properly finds a right-left node" do - # heap.insert(root, hope) - # heap.insert(root, martian) - # expect(heap.find(root, martian.title).title).to eq "The Martian" - # end - # - # it "properly finds a right-right node" do - # heap.insert(root, empire) - # heap.insert(root, mad_max_2) - # expect(heap.find(root, mad_max_2.title).title).to eq "Mad Max 2: The Road Warrior" - # end + heap.insert(district) + expect(heap.find(district.title).title).to eq "District 9" + end + + it "properly finds a left-left node" do + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + expect(heap.find(martian.title).title).to eq "The Martian" + end + + it "properly finds a left-right node" do + heap.insert(pacific_rim) + heap.insert(district) + heap.insert(donnie) + heap.insert(empire) + expect(heap.find(empire.title).title).to eq "Star Wars: The Empire Strikes Back" + end + + it "properly finds a right node" do + heap.insert(district) + heap.insert(empire) + expect(heap.find(empire.title).title).to eq "Star Wars: The Empire Strikes Back" + end + + it "properly finds a right-left node" do + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + heap.insert(hope) + heap.insert(mad_max_2) + expect(heap.find(mad_max_2.title).title).to eq "Mad Max 2: The Road Warrior" + end + + it "properly finds a right-right node" do + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + heap.insert(hope) + heap.insert(mad_max_2) + heap.insert(inception) + expect(heap.find(inception.title).title).to eq "Inception" + end end - # + describe "#delete(data)" do it "handles nil gracefully" do - expect(heap.delete(root_start, nil)).to eq nil + expect(heap.delete(nil)).to eq nil end it "properly deletes a left node" do - heap.insert(root_start, district) - heap.delete(root_start, district.title) - expect(heap.find(root_start, district.title)).to be_nil - end - # - # it "properly deletes a left-left node" do - # heap.insert(root, braveheart) - # heap.insert(root, pacific_rim) - # heap.delete(root, pacific_rim.title) - # expect(heap.find(root, pacific_rim.title)).to be_nil - # end - # - # it "properly deletes a left-right node" do - # heap.insert(root, donnie) - # heap.insert(root, inception) - # heap.delete(root, inception.title) - # expect(heap.find(root, inception.title)).to be_nil - # end - # - # it "properly deletes a right node" do - # heap.insert(root, district) - # heap.delete(root, district.title) - # expect(heap.find(root, district.title)).to be_nil - # end - # - # it "properly deletes a right-left node" do - # heap.insert(root, hope) - # heap.insert(root, martian) - # heap.delete(root, martian.title) - # expect(heap.find(root, martian.title)).to be_nil - # end - # - # it "properly deletes a right-right node" do - # heap.insert(root, empire) - # heap.insert(root, mad_max_2) - # heap.delete(root, mad_max_2.title) - # expect(heap.find(root, mad_max_2.title)).to be_nil - # end + heap.insert(district) + heap.delete(district.title) + expect(heap.find(district.title)).to be_nil + end + + it "properly deletes a left-left node" do + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + heap.delete(martian.title) + expect(heap.find(martian.title)).to be_nil + end + + it "properly deletes a left-right node" do + heap.insert(pacific_rim) + heap.insert(district) + heap.insert(donnie) + heap.insert(empire) + heap.delete(empire.title) + expect(heap.find(empire.title)).to be_nil + end + + it "properly deletes a right node" do + heap.insert(district) + heap.insert(empire) + heap.delete(empire.title) + expect(heap.find(empire.title)).to be_nil + end + + it "properly deletes a right-left node" do + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + heap.insert(hope) + heap.insert(mad_max_2) + heap.delete(mad_max_2.title) + expect(heap.find(mad_max_2.title)).to be_nil + end + + it "properly deletes a right-right node" do + heap.insert(district) + heap.insert(empire) + heap.insert(martian) + heap.insert(hope) + heap.insert(mad_max_2) + heap.insert(inception) + heap.delete(inception.title) + expect(heap.find(inception.title)).to be_nil + end + end + + describe "#printf" do + specify { + expected_output = "Pacific Rim: 72\nBraveheart: 78\nStar Wars: Return of the Jedi: 80\nThe Matrix: 87\nDistrict 9: 90\nStar Wars: The Empire Strikes Back: 94\nInception: 96\nStar Wars: A New Hope: 93\nThe Shawshank Redemption: 91\nThe Martian: 92\nMad Max 2: The Road Warrior: 98\n" + heap.insert(hope) + heap.insert(empire) + heap.insert(jedi) + heap.insert(martian) + heap.insert(pacific_rim) + heap.insert(inception) + heap.insert(braveheart) + heap.insert(shawshank) + heap.insert(district) + heap.insert(mad_max_2) + expect { heap.printf }.to output(expected_output).to_stdout + } + + specify { + expected_output = "Pacific Rim: 72\nStar Wars: Return of the Jedi: 80\nBraveheart: 78\nThe Matrix: 87\nThe Shawshank Redemption: 91\nInception: 96\nDistrict 9: 90\nMad Max 2: The Road Warrior: 98\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nStar Wars: A New Hope: 93\n" + heap.insert(mad_max_2) + heap.insert(district) + heap.insert(shawshank) + heap.insert(braveheart) + heap.insert(inception) + heap.insert(pacific_rim) + heap.insert(martian) + heap.insert(jedi) + heap.insert(empire) + heap.insert(hope) + expect { heap.printf }.to output(expected_output).to_stdout + } end - # - # describe "#print" do - # specify { - # expected_output = "The Matrix: 87\nStar Wars: Return of the Jedi: 80\nStar Wars: A New Hope: 93\nPacific Rim: 72\nInception: 86\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nBraveheart: 78\nThe Shawshank Redemption: 91\nMad Max 2: The Road Warrior: 98\nDistrict 9: 90\n" - # heap.insert(root, hope) - # heap.insert(root, empire) - # heap.insert(root, jedi) - # heap.insert(root, martian) - # heap.insert(root, pacific_rim) - # heap.insert(root, inception) - # heap.insert(root, braveheart) - # heap.insert(root, shawshank) - # heap.insert(root, district) - # heap.insert(root, mad_max_2) - # expect { heap.print }.to output(expected_output).to_stdout - # } - # - # specify { - # expected_output = "The Matrix: 87\nBraveheart: 78\nMad Max 2: The Road Warrior: 98\nPacific Rim: 72\nInception: 86\nDistrict 9: 90\nStar Wars: Return of the Jedi: 80\nThe Shawshank Redemption: 91\nThe Martian: 92\nStar Wars: The Empire Strikes Back: 94\nStar Wars: A New Hope: 93\n" - # heap.insert(root, mad_max_2) - # heap.insert(root, district) - # heap.insert(root, shawshank) - # heap.insert(root, braveheart) - # heap.insert(root, inception) - # heap.insert(root, pacific_rim) - # heap.insert(root, martian) - # heap.insert(root, jedi) - # heap.insert(root, empire) - # heap.insert(root, hope) - # expect { heap.print }.to output(expected_output).to_stdout - # } - # end end diff --git a/01-data-structures/06-trees/min_binary_heap/node.rb b/01-data-structures/06-trees/min_binary_heap/node.rb index d008bce5..76997318 100644 --- a/01-data-structures/06-trees/min_binary_heap/node.rb +++ b/01-data-structures/06-trees/min_binary_heap/node.rb @@ -1,13 +1,9 @@ class Node attr_accessor :title attr_accessor :rating - attr_accessor :left - attr_accessor :right def initialize(title, rating) @title = title @rating = rating - @right = nil - @left = nil end end diff --git a/01-data-structures/06-trees/tree-answers.txt b/01-data-structures/06-trees/tree-answers.txt index e69de29b..d6b55836 100644 --- a/01-data-structures/06-trees/tree-answers.txt +++ b/01-data-structures/06-trees/tree-answers.txt @@ -0,0 +1,58 @@ + + For my implementation of the min heap I opted to use an array. After much +research over different methods to implement a heap I found many developers turned +to this option. I found the author of cracking the coding interview recommended +this option as you don’t need the overhead of a node.right and node.left as elements +are inserted from left and right in a heap anyways. In addition to this the math +for finding a parent is as easy as (index - 2) / 2, the left child (index * 2) + 1, +and the right child (index * 2) + 2. + +Q: Print both Trees to the console and compare the difference between your Binary +Search Tree and your Heap. + +A: After printing both trees to the console there were a couple of key differences. +The min heap would re-arrange on inserting to maintain its heap property. While +the binary search tree would insert to the right or left depending on if it was +greater then or less then the parent value. This meant the order of the printed +values was very different. The lowest value in the min heap will be the root and +the min value in the binary tree will be the left most value. In addition to this +the heap fills in from left to right while the binary search tree fills in depending +if the value is greater then or less then. Making it so the print function shows +the greatest value in the min heap on the bottom row and the search tree the far right. + +Q: How much time does an average insertion consume in the Binary Search Tree +compared to the Heap? + +A: After running the benchmark test on three different insertions for both the +Binary Search Tree and the Min Heap you can see that while they are very close +but the binary search tree has a slight edge. This seems to be because the min +heap has to “heapify” itself upon insert to make sure that the heap property is +maintained. It may have to swap values to get the insert value to the right location. +While the binary search tree must only check if it is greater then less then and +move on. Although when inserting numbers between 1-10,000 the heap when much +quicker, this may be because of my implementation using an array in addition to +no swaps taking place as all were inserted in order. The Binary Search Tree took +quite a bit longer as when inserting it has to make more and more comparisons as +the tree gets larger. + +Q: How much time does finding 5000 in the Binary Search Tree consume compared to the Heap? + +A: When searching for the middle element I found that the binary search tree +performed slightly better. While both were quick the binary search tree performed +better as it used a depth first search and my heap find method breadth first search. + +Q: When would you use a Binary Search Tree and why? + +A: You would use a binary search tree when you need to maintain a changing dataset +in sorted order. Allowing for performant insertions while still being able to utilize +a binary search. + +Q: When would you use an Heap and why? + +A: You would use a heap when ever you would need quick access to the smallest or +largest item as depending on your heap property smallest or largest could be the root. + Insertions are also fast using a heap making it valuable for changing datasets. + +Links to benchmark repl.it +Binary Search Tree: https://repl.it/@ConSou/Ruby-Binary-Search-Tree +Min Heap: https://repl.it/@ConSou/Ruby-Min-Heap