Search and Navigation—Non-Optimal Algorithms
Non-optimal search techniques: depth-first and breadth-first search
To understand these 2 algorithms, we need to look at 2 simple ways we can create a 'to-do list' in a computer program
It is often much easier to solve a big problem as a bunch of much smaller pieces, much like you would try to do by creating to-do lists.
So if your big problem is to clean the house, you may end up writing a bunch of sticky notes for yourself:
My sticky notes for Cleaning the House
Take out the garbage.
Wash the kitchen floor.
Dump scary green food in the refrigerator into the garbage.
Rake the leaves and put them in bags.
Vacuum the rugs.
If you stick one on top of another, you can rip them off as you complete them
Algorithm To Clean the House:
While there are sticky notes in the pile,
Take a sticky note from the top, read it, and do the job
At any time you remember a new job, write it on a sticky and put it on top of the pile
When the pile is empty, the algorithm ends (you're done)
Congratulations—you implemented a stack!
A stack is a data structure in which the last item put (or pushed) into the structure is the first item to be removed from it (LIFO--last in, first out)
In our sticky note example, we put "dump scary food..." on the stack last so it will be the first job we encounter when we remove, or pop jobs off the stack
On a stack data structure, you can only push or pop jobs from the same end (in our sticky note example, the top of the pile)
How come? Because this makes them easy and efficient to understand, create and use
Another, very similar data structure, is a queue
A queue is data structure in which the first item put into the structure is the first item to be removed from it (FIFO--first in, first out)
Unlike a stack, you push jobs onto the queue from one side, and pop them from the other
You may need to click on the following video to start it
There are many ways to create stacks and queues in any programming language but we won't worry about that here
Just think of them as ways to organize the tasks that a program needs to complete
Non-optimal algorithms for searching networks
Non-optimal paths get you from the start to the goal, but not necessarily by incurring the least-cost
They are sufficient to get from the start to goal but maybe not the best possible path
A non-optimal search may find a least-cost path accidentally, but usually it doesn't, especially in larger networks
Our first non-optimal algorithm: depth-first search
To perform depth-first search:
Put the starting node on the empty stack
While the stack is not empty,
Pop a node off the stack
If the node is the goal, stop
Otherwise, expand the node by placing its children on the stack, ordered left to right
Let's work through this with a simple example
Even though each step in the algorithm is simple, the result you get is almost magical
That's what makes search so interesting
Be sure to go through all the examples slowly, and look at them as many times as you need to, until they make sense
We can see from the network and the tree diagrams that there are 2 possible paths from the start to the goal:
0 → 1 → 2 → 3
or
0 → 2 → 3
Don't worry about which one is shorter or faster—depth-first only guarantees to find a path if one exists (not necessarily the least-cost (best) path)
Of all possible start to goal paths, the path that is chosen depends entirely on how the nodes and links in the tree are arranged
Depth-first search uses a stack data structure to organize its work
Important: When you follow the examples in this topic, trace through the tree, not the network
Remember—each branch of the tree is a separate path through the network
In the tree, individual nodes are shown more than once if they occur on more than one path
All the search algorithms here operate on the tree!
Try this out
To replicate this example, follow these steps in Network Search
Make sure Depth First is the selected Search Type in the drop down list
In the app, click to create the nodes as you see them in this example (make sure that the Create Node button is selected)
When you drag the links between your nodes, use the following order:
0 → 1
1 → 2
0 → 2
2 → 3
Other orders will work too (try them), but this one will create a tree identical to the example (to keep things easier for you to follow)
When you finish your network, try clicking the Show Traversal button—it will flash the nodes that the search inspected on its way toward finding a path to the goal
And now, using sticky notes, here we go!
Put the starting node on the empty stack
Ok, Node 0, the starting node, is now on the stack
While the stack is not empty
The stack has one item on it so we keep going
Pop a node off the stack
We look at the item that we popped off the stack
If the node is the goal, stop
Nope, it's not the goal node, so we move on to the next step...
Otherwise, expand the node by placing its children on the stack, ordered left to right
In the tree, we see that the children of node 0 are 1 and 2
I put the nodes on the stack so that node 2 goes on before node 1 (because our self-imposed rule is that we want to look at the left-most child first, and 1 is the left-most child of 0 in the tree)
And now we go back up to the While statement...
While the stack is not empty,
There are 2 node on the stack now
Pop a node off the stack
We look at the item that we popped off the stack
If the node is the goal, stop
Nope, node 1 is not the goal node
Otherwise, expand the node by placing its children on the stack, ordered left to right
Node 1 has only 1 child—node 2
We put node 2 on the stack
But wait! Isn't node 2 already on the stack?
Yes—It is (at the bottom right now), but as part of the path that goes directly from node 0 to node 2
Right now, we're expanding the path that goes from node 1 to node 2
Going back to the top of the while loop, the stack is not empty so we pop off node 2
Remember, this is part of the path that has gone from 0 to 1 to 2
If the node is the goal, stop
No, its not
Otherwise, expand the node by placing its children on the stack, ordered left to right
Node 2 only has 1 child—node 3
We push node 3 onto the stack
And back at the top of the while loop, we see that the stack is still not empty, so...
Pop a node off the stack
And it's the goal node, so we stop!
It's easy to reconstruct the path to the goal node by tracing upward (there's no branching going up—only down)
Who needs a fancy computer when you've got sticky notes?
Our second non-optimal algorithm: breadth-first search
The only difference from depth-first is that breadth-first uses a queue instead of a stack
This creates a left to right sweeping search pattern across a level of a tree before descending to the next level
To perform breadth-first search:
Put the starting node on the empty queue
While the queue is not empty,
Pop a node off the queue
If the node is the goal, stop
Otherwise, put the children of the node at the back of the queue, ordered left to right
To try this out, remember to set the Search Type to Breadth First
Here's how the search works on our search tree: