/******************************************************/ /* This program finds the shortest path between nodes */ /* in a network. It has 8 internal procedures: */ /* SETUP, CONNECT, FIND, PRINT_ALL, PRINT_PATHS, */ /* SHORTEST_DISTANCE, PRINT_ROUTE, and FREE_ALL. */ /******************************************************/ network: procedure options(main); %replace true by '1'b, false by '0'b, citysize by 20, infinite by 32767; declare sysin file; declare 1 city_node based, 2 city_name character(citysize) varying, 2 total_distance fixed, 2 investigate bit, 2 city_list pointer, 2 route_head pointer; declare 1 route_node based, 2 next_city pointer, 2 route_distance fixed, 2 route_list pointer; declare city_head pointer; do while(true); call setup(); if city_head = null then stop; call print_all(); call print_paths(); call free_all(); end; /******************************************************/ /* This procedure reads two cities and then calls the */ /* procedure CONNECT to establish the connection (in */ /* both directions) between the cities. */ /******************************************************/ setup: procedure; declare distance fixed, (city1, city2) character(citysize) varying; on endfile(sysin) goto eof; city_head = null; put skip list('Type "City1, Dist, City2"'); put skip; do while(true); get list(city1, distance, city2); call connect(city1, distance, city2); call connect(city2, distance, city1); end; eof: end setup; /******************************************************/ /* This procedure establishes a single route_node to */ /* connect the first city to the second city by */ /* calling the FIND procedure twice; once for the */ /* first city and once for the second city. */ /******************************************************/ connect: procedure(source_city, distance, destination_city); declare source_city character(citysize) varying, destination_city character(citysize) varying, distance fixed, (r, s, d) pointer; s = find(source_city); d = find(destination_city); allocate route_node set (r); r->route_distance = distance; r->next_city = d; r->route_list = s->route_head; s->route_head = r; end connect; /******************************************************/ /* This procedure searches the list of cities and */ /* returns a pointer to the requested city_node. */ /******************************************************/ find: procedure(city) returns(pointer); declare city character(citysize) varying, (p, q) pointer; do p = city_head repeat(p->city_list) while(p^=null); if city = p->city_name then return(p); end; allocate city_node set(p); p->city_name = city; p->city_list = city_head; city_head = p; p->total_distance = infinite; p->route_head = null; return(p); end find; /******************************************************/ /* This procedure starts at the city_head and displays*/ /* all the cities in the city_list. */ /******************************************************/ print_all: procedure; declare (p, q) pointer; do p = city_head repeat(p->city_list) while(p^=null); put skip list(p->city_name,':'); do q = p->route_head repeat(q->route_list) while(q^=null); put skip list(q->route_distance,'miles to', q->next_city->city_name); end; end; end print_all; /******************************************************/ /* This procedure reads a destination city, calls the */ /* SHORTEST_DISTANCE procedure, and sets the */ /* total_distance field in each city_node to the */ /* total distance from the destination city. */ /******************************************************/ print_paths: procedure; declare city character(citysize) varying; on endfile(sysin) goto eof; do while(true); put skip list('Type Destination '); get list(city); call shortest_distance(city); on endfile(sysin) goto eol; do while(true); put skip list('Type Start '); get list(city); call print_route(city); end; eol: revert endfile(sysin); end; eof: end print_paths; /******************************************************/ /* This procedure is the heart of the program. It */ /* takes an input city (the destination), and computes*/ /* the minimum total distance from every city in the */ /* network to the destination. It then records this */ /* minimum value in the total_distance field of every */ /* city_node. */ /******************************************************/ shortest_distance: procedure(city); declare city character(citysize) varying; declare bestp pointer, (d, bestd) fixed, (p, q, r) pointer; do p = city_head repeat(p->city_list) while(p^=null); p->total_distance = infinite; p->investigate = false; end; p = find(city); p->total_distance = 0; p->investigate = true; do while(true); bestp = null; bestd = infinite; do p = city_head repeat(p->city_list) while(p^=null); if p->investigate then do; if p->total_distance < bestd then do; bestd = p->total_distance; bestp = p; end; end; end; if bestp = null then return; bestp->investigate = false; do q = bestp->route_head repeat(q->route_list) while(q^=null); r = q->next_city; d = bestd + q->route_distance; if d < r->total_distance then do; r->total_distance = d; r->investigate = true; end; end; end; end shortest_distance; /******************************************************/ /* This procedure displays the best route from the */ /* input city to the destination. */ /******************************************************/ print_route: procedure(city); declare city character(citysize) varying; declare (p,q) pointer, (t,d) fixed; p = find(city); do while(true); t = p->total_distance; if t = infinite then do; put skip list('(No Connection)'); return; end; if t = 0 then return; put skip list(t,'miles remain,'); q = p->route_head; do while(q^=null); p = q->next_city; d = q->route_distance; if t = d + p->total_distance then do; put list(d,'miles to',p->city_name); q = null; end; else q = q->route_list; end; end; end print_route; /******************************************************/ /* This procedure frees all the storage allocated */ /* by the program while processing the network. */ /******************************************************/ free_all: procedure; declare (p, q) pointer; do p = city_head repeat(p->city_list) while(p^=null); do q = p->route_head repeat(q->route_list) while(q^=null); free q->route_node; end; free p->city_node; end; end free_all; end network;