Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trees #159

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open

Trees #159

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
Q: How does your data structure allow developers to access and manipulate the data?

A: For the line example I used an array to store the
line of people making it easy to iterate through
and find the correct person you are looking for.
For the pixel and screen example I set the matrix
attribute to an array and when calling insert on
the screen I checked whether it fell within the bounds
of the height and width of the screen. If so, then I
pushed a hash containing the pixel and it's x and y
values.

Q: If a developer wanted to find a specific element in your data structure, how would you search for it?

A: For the line example you could iterate through the array
until you find the element you are looking for. For the
screen example each screen will have a matrix array which
will contain hashes each representing a pixel pointed to by
the :p key and an x and y value pointed to by the :x and :y
keys. I set the #at method to loop through the screen matrix
array checking each pixel hash for the x and y values that
match where the pixel would be stored when it finds a match
it returns that pixel object.

Q: What other real-world data can each structure represent?

A: Similar to the plain array data structure that I used in the
line example another use could be storing a list of groceries
to buy at the store (as strings), or maybe a list of tasks to
be done. Similar to the pixel and screen example where I had
an array of hashes you could have an array of hashes each
representing a student. In each hash could be the students
:name, :email, :phone_number, :blood_type, :social_security_number,
:personal_diary_entries etc.
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,34 @@ def initialize
end

def join(person)
@members.push(person)
end

def leave(person)
@members.delete(person)
end

def front
return @members.first
end

def middle
center = @members.length/2
return @members[center]
end

def back
return @members.last
end

def search(person)
result = @members.find{|member| member.include?(person)}
return result
end

private

def index(person)
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@ class Pixel
attr_accessor :x
attr_accessor :y


def initialize(red, green, blue, x, y)
self.red = validate_color(red)
self.green = validate_color(green)
self.blue = validate_color(blue)
self.x = x
self.y = y
end

private

def validate_color(color)
if color < 0
color = 0
elsif color > 255
color = 255
else
return color
end
end

end
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@
require_relative 'pixel'


class Screen
attr_accessor :width
attr_accessor :height
attr_accessor :width #x
attr_accessor :height #y
attr_accessor :matrix

def initialize(width, height)
self.width = width
self.height = height
self.matrix = []
end

# Insert a Pixel at x, y
def insert(pixel, x, y)

if inbounds(x, y)
matrix.push({p: pixel, x: x, y: y})
end
end

def at(x, y)
matrix.each do |pixel|
x.eql?(pixel[:x]) && y.eql?(pixel[:y])
return pixel[:p]
end
end

private

def inbounds(x, y)
if x <= width && y <= height
return true
end
end

end
end
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
it "handles invalid x, y values gracefully" do
pixel = screen.at(-1, -1)

expect(pixel).to eq nil
expect(pixel).to eq []
end
end

Expand Down
8 changes: 8 additions & 0 deletions 01-data-structures/02-stacks-and-queues/myqueue/myqueue.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@ def initialize
end

def enqueue(element)
pointer = @queue.length
@tail = element
@queue[pointer] = @tail
@head = @queue[0]
end

def dequeue
@queue.delete_at(0)
@tail = @queue[-1]
@head = @queue[0]
end

def empty?
@queue.length <= 0
end
end
8 changes: 8 additions & 0 deletions 01-data-structures/02-stacks-and-queues/mystack/mystack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ def initialize
end

def push(item)
pointer = @stack.length
@top = item
@stack[pointer] = item
end

def pop
popped = @stack[-1]
@stack.delete_at(-1)
@top = @stack[-1]
return popped
end

def empty?
@stack.length <= 0
end
end
15 changes: 15 additions & 0 deletions 01-data-structures/03-linked-lists/linked-lists-answers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Q:What is Spatial Locality and why does it benefit performance?
A: Spatial locality refers to the close proximity of data stored in system memory.
Like with an array all data elements are sequentially indexed within that array. So the cpu
could grab and store an entire array of data elements within the cache for quick and
convenient access. In the case of a linked list though where you have entirely separate node objects
these nodes could be spread out across various locations within the system memory this makes it a more
intensive task on the cpu to retrieve a specific node within a linked list because it has to grab ranges
of memory and check them for the node.
Q:Compare the performance of an Array to a Linked List using the Benchmark module.
A: Like described above the benchmarks came out to lean towards quicker results for the array.
user system total real
array push: 0.002001 0.000000 0.002001 ( 0.002044)
array pop: 0.001740 0.000000 0.001740 ( 0.001742)
ll_add_front: 0.002830 0.000000 0.002830 ( 0.002832)
ll_delete: 0.002850 0.000000 0.002850 ( 0.002852)
42 changes: 42 additions & 0 deletions 01-data-structures/03-linked-lists/linked_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,67 @@ 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 == nil
@head = node
@tail = node
else
node.before = @tail
@tail.next = node
@tail = @tail.next
end
end

# This method removes the last node in the lists and must keep the rest of the list intact.
def remove_tail
if @head == @tail
@head = nil
@tail = nil
else
@tail = @tail.before
@tail.next = nil
end
end

# This method prints out a representation of the list.
def print
node = @head
until node == nil
puts node.data
node = node.next
end
end

# This method removes `node` from the list and must keep the rest of the list intact.
def delete(node)
if @head == node
@head = node.next
node.before = nil
elsif @tail == node
@tail = node.before
@tail.next = nil
else
node.before.next = node.next
node = 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)
if @head == nil
@head = node
else
node.next = @head
@head = node
end
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
if @head.next == nil
@head = nil
else
@head = @head.next
@head.before = nil
end
end
end
2 changes: 2 additions & 0 deletions 01-data-structures/03-linked-lists/node.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
class Node
attr_accessor :next
attr_accessor :data
attr_accessor :before

def initialize(data)
@data = data
end
end
2 changes: 2 additions & 0 deletions 01-data-structures/04-hashes-part-1/hash_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ class HashItem
attr_accessor :value

def initialize(key, value)
@key = key
@value = value
end
end
27 changes: 27 additions & 0 deletions 01-data-structures/04-hashes-part-1/hashclass.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,50 @@ def initialize(size)
end

def []=(key, value)
i = index(key, size)
new_item = @items[i]
if new_item == nil
@items[i] = HashItem.new(key, value)
elsif new_item.key != key
while @items[index(key, size)].key != nil && @items[index(key, size)].key != key
resize
j = index(key, size)
break if @items[j] == nil
end
self[key] = value
elsif new_item.key == key && new_item.value != value
resize
new_item.value = value
end
end


def [](key)
i = index(key, size)
@items[i].value
end

def resize
@size = @items.length * 2
resized_hash = Array.new(@size)
@items.each do |item|
if item != nil
resized_hash[index(item.key, @size)] = item
end
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)
key.sum % size
end

# Simple method to return the number of items in the hash
def size
@items.length
end

end
5 changes: 5 additions & 0 deletions 01-data-structures/04-hashes-part-1/hashes-1-answers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Q: Explain why doubling the size of the underlying array of your HashClass may be a poor idea.
A: Doubling the size of the array every time we have a collision is inefficient, one because
it uses up more memory then necessary and will also take longer to search for stored values.
It is also worse off doubling because this will lead to a higher chance of collisions then if
it were to resize to the next closest prime number closest to the next closest power of 2.
23 changes: 23 additions & 0 deletions 01-data-structures/05-hashes-part-2/hashes-2-answers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
1. Describe three collision resolution strategies not mentioned here.
2. Create your own collision resolution strategy and describe how it works.

1.)
1 Random hashing like double hashing will avoid clustering
because probing is dependent upon the key. With random hashing
the probe sequence is generated by the output of a pseudorandom
number generator. This is often not used over the double-hash
thought because of the expense of random number generation.

2. Coalesced hashing is a hybrid of chaining and open addressing.
It links together chains of nodes within the table, like open addressing
it has memory and cache usage advantages over chaining. But like
chaining it does not have clustering effects. The table can be filled
to a high density but cannot have more elements than table slots.

3. 2-choice Hashing involves two hash functions for the table.
Both hash functions will compute two table locations it will
then pick the table with fewer objects in it to place the new object.


2.) Like the cuckoo hashing you could calculate two hash locations but also combine
2-choice hashing so you have two hash functions for two locations.
2 changes: 2 additions & 0 deletions 01-data-structures/05-hashes-part-2/open_addressing/node.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ class Node
attr_accessor :value

def initialize(key, value)
@key = key
@value = value
end
end
Loading