Ruby Programming – ODIN Project – 4

odinA Bit of Computer Science

In this section, you’ll learn some fundamental computer science concepts that will help you when solving problems with a bit more complexity than just simple web serving. You get to try on your engineering hat and solve some computational problems.


Step 1: A Very Brief Introduction to Computer Science

In the world of programming, there’s a difference between solving a problem the brute force way and solving a problem WELL. We touched on the first layer of this when we covered basic object-oriented programming and how you should break apart your code into well-organized chunks.If you assume those lessons were all about learning how to write good code, these next few lessons are going to be about training yourself to work out the best code to write – the most elegant solution to the problem at hand. It becomes particularly important whenever you start working with large data sets.

Some problems require you to use tools beyond just arrays and iterators. You’re going to build chess and it’s not fundamentally difficult (it’s just a rules-based game after all) but there are some tricks that you’ll want to use to help you solve it. There’s no sense reinventing the wheel when others have already worked out good methods for solving certain types of problems.

Points to Ponder

Look through these now and then use them to test yourself after doing the tasks

  • What is an algorithm?
  • What is pseudo-code?

Your Tasks

1. Look through David Malan’s Introduction to Algorithms What’s an algorithm? (http://ed.ted.com/lessons/your-brain-can-solve-algorithms-david-j-malan)

2. Watch YouTube video What is an Algorithm? (https://www.youtube.com/watch?v=87uzB76-C0c).  Start at 4.00.  This provides a more structured look at solving problems using algorithms.

Uploaded on 14 January 2011
An algorithm is a sequence of unambiguous instructions for solving a computational problem.
3. Read the answers to the Quora question What is the importance of algorithms in web development? (https://www.quora.com/What-is-the-importance-of-algorithms-in-web-development)

Additional Resources


 Step 2: Recursive Methods

Learn how making a function call itself can be helpful for making big problems into smaller problems

Recursion is the idea that a function calls itself. It’s used to take a big problem and start breaking it down into smaller and smaller pieces (“Divide and Conquer“) and continuing to feed their solutions back into the original function until some sort of answer is achieved and the whole chain unwinds.

See Wikipedia’s Divide and conquer algorithms (https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms)
An extract:

In computer science, divide and conquer (D&C) is an important algorithm design paradigm based on multi-branched recursion. A divide and conquer algorithm works by recursively breaking down a problem into two or more sub-problems of the same (or related) type, until these become simple enough to be solved directly. The solutions to the sub-problems are then combined to give a solution to the original problem.

There’s also a right and wrong way to use recursion. The fact is, any problem you can solve recursively you can also solve using iterators. If you find yourself saying “why didn’t I just use a while loop here?” then you probably should have. You won’t often end up using a recursive solution to a problem, but you should get a feel for when it might be a good idea. Some problems also break down into far too many pieces and totally overwhelm your computer’s memory. There’s a balance.

Points to Ponder

Look through these now and then use them to test yourself after doing the tasks

  • Why is recursion a useful technique for solving a big problem?
  • What are the limitations of using recursive solutions?
  • What types of problems are more suited for simple loops than recursion?
  • What is meant by “recursive depth?”
  • What is a “stack overflow” (the concept, not the website)?
  • Why is that relevent to a recursive problem?

Your Tasks

1. Read Dan Nguyen’s The Bastard’s Book of Ruby Chapter on Recursion (http://ruby.bastardsbook.com/chapters/recursion/)

2. Watch Joshua Cheek’s Ruby Kickstart Introduction to Recursion (https://vimeo.com/24716767).  Watch at least up to 17.45.

3. Read the Implementation Issues section of the Wikipedia article Divide and conquer algorithms (https://en.wikipedia.org/wiki/Divide_and_conquer_algorithms#Implementation_issues) to get an overview of some of the limitations of recursion.


 Test Yourself

  1. Complete the Ruby Computer Science – Recursion Quiz from CodeQuizzes (http://www.codequizzes.com/computer-science/recursion)

 Additional Resources


Project: Recursion

Introductory Task: Fibonacci

The Fibonacci Sequence, (See Wikipedia’s Fibonacci number (https://en.wikipedia.org/wiki/Fibonacci_number)) which sums each number with the one before it, is a great example of a problem that can be solved recursively.


 Your Tasks

1. Write a method #fibs which takes a number and returns that many members of the fibonacci sequence. Use iteration for this solution.

2. Now write another method #fibs_rec which solves the same problem recursively. This can be done in just 3 lines.


Project: Merge Sort

We spent some time early on dealing with sorting (ie. bubble sort). Now it’s time to take another look at sorting with Merge Sort (https://en.wikipedia.org/wiki/Merge_sort) a type of sort that lends itself well to recursion and can be much faster than bubble sort on the right data sets. You’ll build a method which sorts a given array but uses a “merge sort” method for doing so.


 Background Viewing

The first step is to actually understand what the merge sort algorithm is doing:

1. Watch the YouTube video Merge Sort (https://www.youtube.com/watch?v=EeQ8pwjQxTM) from Harvard’s CS50x course.

Published on 26 Sep 2012

2. Watch the YouTube video Merge sort – how it works (1) (https://www.youtube.com/watch?v=OAsokGNa18k) fot a more formal look at the concepts,

Uploaded on 16 February 2011
Merge sort is based on the Divide-and-Conquer design strategy.
3, Watch the YouTube video Merge sort – how it works (2) (https://www.youtube.com/watch?v=nNhpFO9CmPs)
https://www.youtube.com/watch?v=nNhpFO9CmPs
Uploaded on 16 February 2011
The merge step of merge sort constructs a sorted array by merging two smaller sorted arrays, in linear time.

Your Tasks

1. Build a method #merge_sort that takes in an array and returns a sorted array, using a recursive merge sort methodology.

2. Tips:

  • Think about what the base case is and what behavior is happening again and again and can actually be delegated to someone else (ie. that same method!).
  • It may be helpful to check out the background videos again if you don’t quite understand what should be going on.

Additional Resources


Step 3: Common Data Structures and Algorithms

Learn why we use different data structures to handle our data and some classic algorithms for searching through them to help solve problems

The basic idea of a data structure is to store data in a way that meets the needs of your particular application. You might be inclined to store a particular kind data in one giant array, but it would be rather time consuming to locate a specific value if you had a significant number and depth of items. So you need to look to other options.

Depending on the application, there are a batch of other basic data structures available to help you out. The differences between them typically have to do with trade-offs between how long it takes to first populate the structure, how long it takes to add or find elements, and how large the structure is in memory.

You should be able to identify and solve certain problems where plain old Arrays, Hashes and Sets are not appropriate. New structures and strategies will be particularly relevant, for instance, when you’re trying to search through a large batch of data for a particular value or plan out a strategy several moves in advance.

You’ve already had a brief introduction to algorithms over some of the other lessons and you even got to write your own Merge Sort algorithm in the last project. You’ll find that sorting algorithms are quite common. Another major area for algorithms is in search, where milliseconds count. When you’re searching through enormous troves of data, the quality of your search algorithm is incredibly important. Traversing a data tree looking for a particular element is a related problem that’s common in data intensive applications.

Luckily for you, these complex algorithmic problems have all been solved many times in the past. Understanding how they are solved will give you some great tools to apply to other (similar) problems on your own. Algorithms are really just ways of solving problems systematically. In this brief introduction, we’ll focus on a couple of algorithms that you may run into when coding on your own – breadth-first-search and depth-first-search.


 Points to Ponder

Look through these now and then use them to test yourself after doing the tasks

  • What is a data structure?
  • What is a stack?
  • What is a queue?
  • What’s the difference between a stack and a queue?
  • What is a stack useful for?
  • What is a queue useful for?
  • What’s the best way to implement stacks and queues in Ruby (hint: think simple)?
  • Why bother having many different search algorithms?
  • What is breadth-first-search (BFS)?
  • What is depth-first-search (DFS)?
  • What situations would you want to use BFS?
  • What situations would you want to use DFS instead?
  • When would BFS be impractical?

 Your Tasks

1. Look at Wikipedia‘s article on Data structure (https://en.wikipedia.org/wiki/Data_structure) for a high level overview.

2. Watch the YouTube video Stacks and queues: the basics (https://www.youtube.com/watch?v=6QS_Cup1YoI)

Uploaded on 20 January 2012
What are stacks and queues? When are they useful?
3, Watch this video from Harvard’s CS50x course (http://cs50.tv/2012/fall/shorts/binary_search/binary_search-720p.mp4) to learn about binary search trees.
3. Watch this YouTube video Coursera – Design and Analysis of Algorithms I – 1.1 Introduction : Why Study Algorithms ? from ‘Coursera’s Algorithms course (https://www.youtube.com/watch?v=u2TwK3fED8A)
https://www.youtube.com/watch?v=u2TwK3fED8A
Published on 14 March 2012
4. Read A Gentle Introduction to Algorithms for Web Developers (http://www.giocc.com/a-gentle-introduction-to-algorithms-for-web-developers.html)
5. Watch the YouTube video Graph Traversals :: Depth first search (DFS) & Breadth First Search (BFS) Algorithms (https://www.youtube.com/watch?v=zLZhSSXAwxI)
https://www.youtube.com/watch?v=zLZhSSXAwxI
Uploaded on 28 December 2011
Graph ADT how-to – performing a:
– Breadth-first Traversal
– Depth-first Traversal

Additional Resources


Project: Data Structures and Algorithms

Project 1: Searching Binary Trees

You learned about binary search trees (https://en.wikipedia.org/wiki/Binary_search_tree) where you take a group of data items and turn them into a tree full of nodes where each left node is “lower” than each right node. The tree starts with the “root node” and any node with no children is called a “leaf node”.

You also learned about tree search algorithms like breadth-first-search and depth-first-search. You learned that BFS is best used to find the optimum solution but can take a very long time (impractically long for broad and deep data sets) while DFS is often much faster but will give you the FIRST solution, not necessarily the best. Here you’ll get a chance to implement both.


Your Tasks

You’ll build a simple binary tree data structure from some arbitrary input and also the “crawler” function that will locate data inside of it.

1. Build a class Node. It should have a value that it stores and also links to its parent and children (if they exist). Build getters and setters for it (ie. parent node, child node(s)).

2. Write a method build_tree which takes an array of data (ie. [1, 7, 4, 23, 8, 9, 4, 3, 5, 7, 9, 67, 6345, 324]) and turns it into a binary tree full of Node objects appropriately placed. Start by assuming the array you get is sorted.

3. Now refactor your build_tree to handle data that isn’t presorted and cannot be easily sorted prior to building the tree. You’ll need to figure out how to add a node for each of the possible cases (ie. if it’s a leaf versus in the middle somewhere).

4. Write a simple script that runs build_tree so you can test it out.

5. Build a method breadth_first_search which takes a target value and returns the node at which it is located using the breadth first search technique. Tip: You will want to use an array acting as a queue to keep track of all the child nodes that you have yet to search and to add new ones to the list (as you saw in the video Graph Traversals :: Depth first search (DFS) & Breadth First Search (BFS) Algorithms (see above). If the target node value is not located, return nil.Build a method depth_first_search which returns the node at which the target value is located using the depth first search technique. Use an array acting as a stack to do this.

6. Next, build a new method dfs_rec which runs a depth first search as before but this time, instead of using a stack, make this method recursive.

7. Tips:

  • You can think of the dfs_rec method as a little robot that crawls down the tree, checking if a node is the correct node and spawning other little robots to keep searching the tree. No robot is allowed to turn on, though, until all the robots to its left have finished their task.
  • The method will need to take in both the target value and the current node to compare against.

Project 2: Knight’s Travails

A knight in chess can move to any square on the standard 8×8 chess board from any other square on the board, given enough turns.  See this animation (https://upload.wikimedia.org/wikipedia/commons/c/ca/Knights-Tour-Animation.gif). Its basic move is two steps forward and one step to the side. It can face any direction.

All the possible places you can end up after one move look like this:


Your Tasks

Your task is to build a function knight_moves that shows the simplest possible way to get from one square to another by outputting all squares the knight will stop on along the way.

You can think of the board as having 2-dimensional coordinates. Your function would therefore look like:

  • knight_moves([0,0],[1,2]) == [[0,0],[1,2]]
  • knight_moves([0,0],[3,3]) == [[0,0],[1,2],[3,3]]
  • knight_moves([3,3],[0,0]) == [[3,3],[1,2],[0,0]]

Put together a script that creates a game board and a knight.

1. Treat all possible moves the knight could make as children in a tree. Don’t allow any moves to go off the board.

  • Decide which search algorithm is best to use for this case. Hint: one of them could be a potentially infinite series.
  • Use the chosen search algorithm to find the shortest path between the starting square (or node) and the ending square. Output what that full path looks like, ie.:

> knight_moves([3,3],[4,3]) You made it in 3 moves! Here's your path: [3,3] [4,5] [2,4] [4,3]


Additional Resources

https://www.youtube.com/watch?v=pJ6aeg8x1Ig
Published on 20 April 2013
Video from Coursera – Princeton University – Course: Algorithms, Part I