Steps to the Shortest Path
Army of Ants method
- Create a struct to represent a city. Perhaps just name, longitude, latitude,
population; it is easy to add more later when needed.
- Create an array of pointers to city objects. An array is NOT really good
enough, but if you program modularly, if you use an even slightly object oriented approach, it
will be easy to replace the array with a Vector, A FlexArray, or a Linked List
at some point in the future. Let's just get it working.
- Read the data file into the array, and make sure it has been read correctly.
A good test is to enter an interactive loop: you type a city name, and it
finds the city and reports ann known information about it.
- Design a struct to represent a road, containing a string for name, number for length, and
city* pointers for each of the citirs it connects. Don't bother to make an
array for all the roads.
- Read the roads data. As you read each road record, look up the names of the cities that
it connects (in the already-existing-and-tested array of cities). Create a proper road*
object containing the appropriate city* values. Test it. For every road that you read from the file,
print all of its data plus all of the data for the two cities that it connects. Now you
know that it is working properly.
- Add to your city struct a short array of road *'s. An array really
really isn't good enough, but again, let's get it working, then replace the works with
something better. That is what modular deisgn is all about.
- Modify your road reader: for every record that it reads from the file, it should create
two copies of the road object, identical in every way except that the two city*
values are swapped around. The two copies of the road object are added to the array of roads for
each of the cities that they connect.
So now every city in your big array contains a name, position, population, and
array of (pointers to) road objects. Each of those road objects contains a name, length,
and two pointers to city objects.
- Test the program so far with some user controlled exploration: The program always remembers
the "current city" while executing a simple loop. At each stage:
- Print the current city's name and details.
- Print the list of all roads leading from that city.
- Let the user select one of those roads (perhaps just entering a number: 3 means the 3rd
road in the list).
- Follow that road, seeting "current city" to whatever city is at the other end of it.
- Repeat, until you are sure everything is perfect.
Make sure you can accurately navigate throughout the world this way.
- Ask the user where their starting point is. Create a heap containing just that one city.
It is a very small heap, but will soon grow. A heap with just one entry requires no effort to create.
Cities will be added to and removed from this heap as the shortest path algorithm progresses.
Heaps require that their contents have some indication of their importance or priority.
Add to the city struct a number, the ETA for the army of ants arriving at that city. The
ETA member of a city is the priority value used to order the heap.
- The Big Main Loop
- Remove from the heap the city that has the lowest (highest priority) ETA. If the
heap is empty, the loop stops. Remember to repair the heap after removing the first city.
The removed city becomes the "current city".
- Set the global "time now" variable to that city's ETA. Your army of ants has just arrived at the
seletcted city, and that is the time.
- Look at every road leading from the current city. There are N roads leading out of it.
"C0" represents the current city. "T0" is the time now (ETA for that C0).
"N" is the number of roads leading out of it. "Ri" is the
length of the ith road. "Di" is the city at the other end of the ith road.
For each i in 0...N-1:
- Compute a new ETA for the city at the other end of the ith road: Ti = T0 + Ri.
- If Ti is greater than or equal to the ETA already recorded for that city, then ignore it.
We already know a shorter way to get there, this road adds nothing useful.
- If The other city is not already in the heap, add it. Its priority is the ETA, Ti, just
computed. Make sure you do a proper heap addition, so the new city finds its correct position
in the heap.
- If the other city is already in the heap, but the ETA previously worked out for it is
greater than the new one, Ti, then change its ETA to Ti, and correct the heap. The adjusted
city may have to move closer to the top of the heap.
- Repeat for each of the N roads leading from C0.
Note for the previous steps: How do you know whether city X is already in the heap? Easy: add
to each city struct a "where" member. "Where" is initially 0, indicating "not in the heap".
Whenever a city is added to the heap, its "where" is set to its position in the heap. Whenever
a city's position in the heap is adjusted, its "where" is also adjusted. Thus, you can always
find whether and where a city is already in the heap without any kind of searching.
- Make sure it worked.
The Big Main Loop contnues until the heap is empty. After the loop becomes empty, enter
another very siple loop. This one just runs through the entire array of cities, printing for
each its name and ETA. Of course, all those printed ETAs are now in the past, but if you look at
the map, you will see that what was printed is actually the lengths of the shortest paths
from the starting city to every toher city. Check that the results are correct.
- Now ask the user what the destination city was. You have already worked out how far it is
from the start point, before you ever knew what it was. By working backwards, you can easily
find the sequence of roads that constitute the shortest path.
For example, if you know the shortest path from Amman to Zanzibar is 100 miles long, and there are only
three roads leading into Zanzibar, you want to know which of those three is actually part of the
100-mile long shortest path. Let's say that the three roads leading in to Z are Interstate 17
(which is 40 miles long, and connects to Kalamazoo), the Via Apia (25 miles long, leading to
Rome), and the B-4393 (3 miles long, leading to Llaneyllin). Which is the right one? Look
at the shortest distances (old ETAs) for the cities: If I-17 is the correct road, the shortest
path from Amman to Kalamazoo must be 100-40 = 60 miles. If the Apian Way is correct, then the
shortest distance from Amman to Rome must be 100-25 = 75 miles. If the B-4393 is the right way,
then the shortest distance from Amman to Llaneyllin must be 100-3 = 97 miles. One of those
must be the already-caulculated shortest distance to the appropriate city, that tells you which
road to take. In this way, it is easy to work all the way back to Amman, and print the whole
list of roads.
- Draw the picture. Make the results look good. At least print out the route in a clear,
user-friendly manner.
- Now remember to go back and change your arrays to nice efficient structures.