Editing Recursive function

Jump to: navigation, search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.
Latest revision Your text
Line 54: Line 54:
 
</syntaxhighlight>
 
</syntaxhighlight>
 
''(Note that function names are not allowed to start with uppercase letters in Haskell.)''
 
''(Note that function names are not allowed to start with uppercase letters in Haskell.)''
 
==Philosophy==
 
===Statement===
 
Recursion is a powerful tool for solving problems, but it is not always obvious how to approach a problem recursively. The general principle, often called '''divide and conquer''', is as follows:
 
 
{{ImportantConceptBox|Identify instances of your problem that are so small or simple that they are trivial. Determine how to break a large or complex instance into one or more smaller or simpler instances so that the solution to the latter can be used to determine a solution to the former. By repeating this process enough times, it is possible to solve any instance, no matter how large, by reducing it to trivial pieces.}}
 
 
===Non-computer science examples===
 
This philosophy is not restricted to computer science. Below we give some examples from other fields that may assist the reader in internalizing the divide and conquer philosophy and appreciating its ubiquity. When the solution to an instance requires the solutions to simpler instances, those simpler instances will be indented an additional level to show this relationship.
 
 
'''Problem''': Climb a ladder. The generic form of this problem is ''Be at the top of the ladder''. The instance is where you already are. Hence, climbing from the bottom to the top and climbing from the middle to the top are both the same problem, but different instances of it.
 
 
'''Solution''': If you are already at the top, this is a trivial instance; you don't actually have to do anything. If you are not at the top, suppose there are <math>x</math> rungs remaining, where <math>x > 0</math>. Notice that the problem would be easier to solve if there were only <math>x-1</math> rungs separating you from the top of the ladder. So climb up one rung; this will reduce the instance at hand to an easier one. Repeat as necessary.
 
 
'''Example instance''':
 
:You are 4 rungs away from the top of the ladder. The instance would become simpler if you were only 3 rungs away from the top, so climb up one rung.
 
::You are 3 rungs away from the top of the ladder. The instance would become simpler if you were only 2 rungs away from the top, so climb up one rung.
 
:::You are 2 rungs away from the top of the ladder. The instance would become simpler if you were only 1 rung away from the top, so climb up one rung.
 
::::You are 1 rung away from the top of the ladder. The instance would become simpler if you were only 0 rungs away from the top, so climb up one rung.
 
:::::You are at the top of the ladder. Congratulations! You've solved the problem.
 
 
 
'''Problem''': Differentiate a function with respect to <math>x</math>. The generic form of this problem is ''Differentiate with respect to <math>x</math>''. The instance is the specific function you want to differentiate.
 
 
'''Solution''': If the function to be differentiated is a power of <math>x</math>, a constant, or a standard function of <math>x</math> (for example, <math>\sin x</math>), this is a trivial instance; you can simply use the power rule or look up the derivative in your calculus textbook. Otherwise, find the last step in computing the function; it may be addition, subtraction, multiplication, division, or a function application. Then use the sum rule, difference rule, product rule, quotient rule, or chain rule, as appropriate, on the subexpression(s), which is/are necessarily simpler than the original function. By applying these rules enough times, any elementary function can be differentiated.
 
 
'''Example instance''':
 
:We wish to differentiate <math>\log x + e^{x^2/2}</math>. This is a complex instance. The lowest-precedence operation is the addition, so we will use the sum rule; hence, <math>\frac{d}{dx} \left(\log x + e^{x^2/2}\right) = \frac{d}{dx} \log x + \frac{d}{dx} e^{x^2/2}</math>. Each of the two derivatives on the right side is a simpler instance of this problem.
 
::We wish to differentiate <math>\log x</math>. This is a trivial instance, since the textbook will tell you that <math>\frac{d}{dx} \log x = 1/x</math>.
 
::We wish to differentiate <math>e^{x^2/2}</math>. The lowest-precedence operation is the exponential; it is done last. So we will use the chain rule, hence, <math>\frac{d}{dx} e^{x^2/2} = \left(\lambda x.\frac{d}{dx}e^x\right)\frac{x^2}{2} \frac{d}{dx} \frac{x^2}{2}</math>.
 
:::We wish to differentiate <math>e^x</math>. This is a trivial instance; the textbook indicates that its derivative is <math>e^x</math>.
 
:::We wish to differentiate <math>x^2/2</math>. This is a complex instance; we use the rule <math>\frac{d}{dx} kf(x) = k\frac{d}{dx}f(x)</math>, where <math>k</math> is a constant. Thus, <math>\frac{d}{dx} x^2/2 = \frac{1}{2} \frac{d}{dx}x^2</math>.
 
::::We wish to differentiate <math>x^2</math>. This is a trivial instance; the power rule gives its derivative as <math>2x</math>.
 
:::Therefore, the derivative of <math>x^2/2</math> is <math>\frac{1}{2}(2x) = x</math>.
 
::Therefore, the derivative of <math>e^{x^2/2}</math> is <math>\left(\lambda x.e^x\right)\frac{x^2}{2}\cdot x = xe^{x^2/2}</math>.
 
:Therefore, the derivative of <math>\log x + e^{x^2/2}</math> is <math>1/x + xe^{x^2/2}</math>. Congratulations! You've solved the problem.
 
 
 
'''Problem''': Obtain a certain item. The generic form of this problem is ''Obtain''. The instance is the specific item you wish to obtain.
 
 
'''Solution''': If you already have the item, then you don't need to do anything; this is a trivial instance. If the item is commercially available and you wouldn't mind buying it, then simply do so; this is also a trivial instance. Otherwise, build it yourself. Identify simpler components of which the item is composed. Obtaining these components comprises easier instances of the given problem. After obtaining the required components, assemble them into the item desired.
 
 
'''Example instance''':
 
:You live on a farm and want to prepare a rack of ribs for dinner. This is a complex instance. To solve it, you will have to first obtain the ribs and the barbecue sauce.
 
::You wish to obtain a rack of ribs. This is a complex instance; you will need need to slaughter and butcher a pig.
 
:::You wish to obtain a pig. You don't raise pigs on your farm, but your neighbour raises pigs. This is a trivial instance, as you can simply buy a pig from your neighbour.
 
::You have obtained a pig. Now slaughter and butcher it. You have obtained a rack of ribs.
 
::You wish to obtain barbecue sauce. Unfortunately, you don't have any left, and your neighbour doesn't either, and it's a holiday, so the market is closed. This is a complex instance. You look in your cookbook, and find a recipe for barbecue sauce consisting of ketchup, sugar, and vinegar. You will need to obtain these and mix them.
 
:::You wish to obtain ketchup. You already have ketchup, so this is a trivial instance.
 
:::You wish to obtain sugar. You already have sugar, so this is a trivial instance.
 
:::You wish to obtain vinegar. You already have vinegar, so this is a trivial instance.
 
::Having obtained ketchup, sugar, and vinegar, you mix them in the correct ratios, thereby obtaining barbecue sauce.
 
:Having obtained ribs and barbecue sauce, you apply the sauce to the ribs, apply heat, and then apply more sauce. Congratulations! You have obtained a dish of ribs, ready to enjoy.
 
 
===Examples from computer science===
 
'''Problem''': Given two non-negative integers <math>x</math> and <math>y</math>, find their greatest common divisor (GCD), denoted <math>\gcd(x,y)</math>. The general form of the problem is ''compute the GCD''. The specific instance is given by <math>x</math> and <math>y</math>.
 
 
'''Solution''': If <math>x=0</math>, we have a trivial case, and the answer is <math>y</math>. If <math>y=0</math>, again it is a trivial case, and the answer is <math>x</math>. Otherwise, we have a complex case. But if we can somehow make one of the numbers smaller, the problem will become simpler, and ultimately one of the two numbers will have to reach zero. It turns out that <math>\gcd(x,y) = \gcd(x,y-x)</math>, if <math>x \leq y</math> (and the reverse, <math>\gcd(x,y) = \gcd(x-y,y)</math> if <math>x \geq y</math>). By reducing the problem to one of these two possible subproblems, and repeating enough times, we eventually discover the answer.
 
 
'''Example instance''':
 
:We wish to find the GCD of 30 and 48. Since neither is 0, this is a complex case. We note that <math>\gcd(30,48) = \gcd(30,18)</math>.
 
::We wish to find the GCD of 30 and 18. Since neither is 0, this is a complex case. We note that <math>\gcd(30,18) = \gcd(12,18)</math>.
 
:::We wish to find the GCD of 12 and 18. Since neither is 0, this is a complex case. We note that <math>\gcd(12,18) = \gcd(12,6)</math>.
 
::::We wish to find the GCD of 12 and 6. Since neither is 0, this is a complex case. We note that <math>\gcd(12,6) = \gcd(6,6)</math>.
 
:::::We wish to find the GCD of 6 and 6. Since neither is 0, this is a complex case. We note that <math>\gcd(6,6) = \gcd(6,0)</math>.
 
::::::We wish to find the GCD of 6 and 0. This is a trivial case, and the answer is 6.
 
 
'''Implementation''' (C):
 
<syntaxhighlight lang="cpp">
 
int gcd(int x, int y)
 
{
 
  if (x == 0) return y;
 
  else if (y == 0) return x;
 
  else if (x >= y) return gcd(x-y, y);
 
  else return gcd(x, y-x);
 
}
 
</syntaxhighlight>
 
 
 
'''Problem''': Locate a file by name on a filesystem, or conclude that the file does not exist. The problem here is ''find if exists''; the instance consists of the filename of the file we wish to find, and the directory that we wish to search.
 
 
'''Solution''': If the directory is empty, this is a trivial instance, and we give up. Otherwise, we will have to examine the contents of the directory. For each entry of the directory, if it is a file, check whether it matches the given filename; if so, we are done. If not, go on to the next one. If the entry is a directory itself, this is a subinstance of the problem: attempt to locate the desired file in the subdirectory; again, if we succeed, then we are done, and otherwise, we must go on to the next entry.
 
 
'''Example instance''':
 
:We wish to locate the file <code>apache2.conf</code> somewhere under the root directory of a Unix-like system. The root directory is not empty; it contains the entries: <code>bin/ dev/ etc/ home/ lib/ proc/ root/ tmp/ usr/ var/</code>
 
::We wish to locate the file <code>apache2.conf</code> somewhere in <code>/bin</code>. This directory is not empty; it contains the entries: <code>cat chgrp chmod chown cp date dd df echo</code> ... and no subdirectories. None of these matches the desired filename, so we give up. (This turned out to be a trivial instance, since this directory contains no subdirectories on which to recurse.)
 
::We wish to locate the file <code>apache2.conf</code> somewhere in <code>/dev</code>. This directory is not empty; it contains the entries: <code>console full mem null port ptmx pts/ random sda sda1 stderr stdin stdout tty zero</code>. We check each of these in turn: no, no, no, no, no, no... a directory. We have to search <code>pts/</code> for the file.
 
:::We wish to locate the file <code>apache2.conf</code> somewhere in <code>/dev/pts</code>. This directory is empty, so this is a trivial instance, and we give up.
 
::We continue trying to match against <code>random</code> and so on: no, no, no, no, no, no, no, no. We give up; the file <code>apache2.conf</code> is not in <code>/dev</code>.
 
::We wish to locate the file <code>apache2.conf</code> somewhere in <code>/etc</code>. This directory is not empty; it contains the entries: <code>apache2/ crontab fstab group gshadow hostname hosts inittab localtime motd passwd profile resolv.conf shadow shells X11/</code>.
 
:::We wish to locate the file <code>apache2.conf</code> somewhere in <code>/etc/apache2</code>. This directory is not empty; it contains the entries: <code>apache2.conf conf.d/ envvars httpd.conf magic mods-available/ mods-enabled/ ports.conf sites-available/ sites-enabled/</code>. We find a match at the first entry; success!
 
 
'''Implementation''' (Python):
 
<syntaxhighlight lang="python">
 
import os
 
 
def find(path, name):
 
  for entry in os.listdir(path):                              # iterate through every entry
 
    newpath = os.path.join(path, entry)                        # get the absolute path to this entry
 
    if os.path.isdir(newpath) and not os.path.islink(newpath): # descend into directory
 
      print "Descending into directory " + newpath
 
      ret = find(newpath, name)                                # complex case; recurse into subproblem
 
      if ret:
 
        return ret
 
    else:                                                      # it's a file; just check whether it matches
 
      if entry == name:
 
        return newpath
 
  return False                                                # give up
 
 
res = find("/", "apache2.conf")
 
if res:
 
  print "File found at " + res
 
else:
 
  print "File not found"
 
</syntaxhighlight>
 
 
[[Category:Incomplete]]
 

Please note that all contributions to PEGWiki are considered to be released under the Attribution 3.0 Unported (see PEGWiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

Cancel | Editing help (opens in new window)

Template used on this page: