My advice would be to start by practicing small algorithms first, then move on to larger onesAnd by small, I mean small. Not binary-search-sized, even that is too big.
Start by giving yourself two functions: "add1" (adds one to a number) and "sub1" (subtracts 1 from a number). Then build normal addition:
def add(x, y):
if y == 0:
return x
else:
return add(add1(x), sub1(y))
This is a pretty simple algorithm, but it helps to get you in the right frame of mind to figure out larger ones.
The Little Schemer series of books is a great (albeit quirky) introduction to stuff like this (and other things too).
Without a goal or focus it can be hard to find algorithms that have meaning. Writing algorithms without a goal leaves you without focus and, although you may have written some good functions it'll be harder to know where they can be properly applied without some form of goal or project to work towards.
To me, an appropriate way to learn is to conceptualize a goal. If what you want to start with is a calculator then make one using only the basic +, - operators and maybe binary functions if you care to. Modulus, Multiplication, Power functions, Division and others can be accomplished with simple uses of +/- and building up from there.
For me, a good project was a mobile game that uses a home built physics engine. Collission detection, "bouncing", gravity and the complexity of sprite drawing/manipulation was enough of a goal to apply moderately complex trig that was essential in school. I now have a portfolio of very diverse and extremely useful sprite functions that I built on my own that I can reuse in other projects.
I wrote my own heuristic algorithm for battleship that I'd argue is the best possible AI without allowing it to have memory or cheating... it all started with looking at the problem space and determining how simple things I already know (stats) applied to the problem and figured how to apply it from there.
That reminds me of the classic and occasionally useful multiplication algorithm.
mult(x,y):
int total = 0;
do
{
if (x & 1) total += y; // if x's last bit is true add y
x = x >> 1; //binary shift right 1 to divide x by 2.
y = y << 1; //binary shift left 1 to multiply y by 2.
}while (x > 0);
return total;
which I tend to use as an intro to algorithms because it's useful and short. But, just complex enough to think about.
In addition to the delightful Little Schemer, I'd also recommend Project Euler problems, maybe work up to working through SICP or interesting bits in Art of Computer Programming.
Project Euler's problems are nice, but they get hard fast. It's nice to apply and practice some theoretical knowledge this way, but no way to acquire that knowledge in the first place.
I like that the Project Euler problems get hard fast, it's a great opportunity to fail over and over again, which (at least for me) forces you to think more deeply about the problems, when something is too easy you can fall into the trap of a "good enough" solution, which is often appropriate in the day job, but not necessarily so when you are trying to practice. I love the code golf option on 4clojure for that also, because for so many of the problems I just can't see how people get the smallest solutions - not that I would want to write code like that for a shipping product.
Project Euler is fun and all that. But no real way to learn about all those techniques you need in the first place. A particularly hard problem might set you off learning about stuff in that direction. I'm still working on a way to generalize my dynamic programming knowledge enough to solve problem 256 at the moment. Problem 202 was fun, when you realized what the problem was really about.
Start by giving yourself two functions: "add1" (adds one to a number) and "sub1" (subtracts 1 from a number). Then build normal addition:
This is a pretty simple algorithm, but it helps to get you in the right frame of mind to figure out larger ones.The Little Schemer series of books is a great (albeit quirky) introduction to stuff like this (and other things too).