在图的遍历算法的基础上我们可以来实现Dijkstra算法了。Dijkstra算法的基本思想就是计算出图中从起点到所有节点的最短路径。
每个节点只需要记住从起点到自己的最短路径和最短路径对应的父节点信息就可以了。算法的具体情况我这里就不赘述了,大家感兴趣的话可以百度一下。代码在CodeBlocks下测试通过。
graph.h代码:
#ifndef _GRAPH_H
#define _GRAPH_H
typedef struct _graph_node GRAPH_NODE;
typedef struct _graph_route_list GRAPH_ROUTE_LIST;
#define NODE_COST_INF 9999
typedef struct _node_info
{
int cost;/*the least cost from start to this node*/
GRAPH_NODE *parent; /*the parent for the least cost link */
BOOL Dijkstra_done;
}NODE_INFO;
typedef struct _graph_link
{
int cost;
GRAPH_NODE *neigh_node;
struct _graph_link *next;
}GRAPH_LINK;
typedef struct _graph_node
{
char *name;
NODE_INFO info;
GRAPH_LINK *neigh_link; /*node neighbour info*/
struct _graph_node *next;
}GRAPH_NODE;
typedef struct _graph_node_list
{
GRAPH_NODE *head;
}GRAPH_NODE_LIST;
typedef struct _graph_route{
GRAPH_NODE *node;
GRAPH_LINK *link;
int route_key;
struct _graph_route *next;
}GRAPH_ROUTE;
typedef struct _graph_route_list
{
GRAPH_ROUTE *route_head;
int cost;
struct _graph_route_list *next;
}GRAPH_ROUTE_LIST;
typedef struct _graph
{
GRAPH_NODE *start;
GRAPH_NODE *end;
int least_cost;
GRAPH_ROUTE_LIST *route_list_head;
GRAPH_NODE *node_head;
}GRAPH;
void graph_print(GRAPH *g);
void graph_traverse(GRAPH *g);
GRAPH* graph_init(void);
void graph_config(GRAPH *g,GRAPH_NODE *start,GRAPH_NODE *end);
GRAPH_NODE* graph_add_node(GRAPH *g,char *name);
RV graph_add_neigh(GRAPH_NODE *node,GRAPH_NODE *neigh_node,int cost);
void graph_Dijkstra_traverse(GRAPH *g);
void graph_Dijkstra_print(GRAPH *g);
#endif
graph.c 代码
#include
#include
#include
#include
#include
#include "define.h"
#include "graph.h"
static void node_print(GRAPH *g,GRAPH_NODE *node,int level);
static void node_traverse(GRAPH *g,GRAPH_ROUTE_LIST *route_list,GRAPH_NODE *node);
static void level_print(int level)
{
while(level--)printf("\t");
return;
}
static void link_print(GRAPH *g,GRAPH_LINK *link,int level)
{
level_print(level);
printf("link cost=%d\n",link->cost);
return;
}
static void node_neigh_print(GRAPH *g,GRAPH_LINK *neigh_link,int level)
{
level++;
while(neigh_link)
{
link_print(g,neigh_link,level);
node_print(g,neigh_link->neigh_node,level);
neigh_link = neigh_link->next;
}
return;
}
static void node_print(GRAPH *g,GRAPH_NODE *node,int level)
{
if(!node)return;
level_print(level);
printf("node %s --->:\n",node->name);
node_neigh_print(g,node->neigh_link,level);
return;
}
void graph_route_print(GRAPH_ROUTE *route)
{
while(route)
{
printf("node %s --->:\n",route->node->name);
route = route->next;
}
}
void graph_print(GRAPH *g)
{
GRAPH_ROUTE_LIST *route_list;
assert(g);
route_list = g->route_list_head;
while(route_list)
{
printf("route list cost=%d\n",route_list->cost);
graph_route_print(route_list->route_head);
route_list = route_list->next;
}
return;
}
GRAPH* graph_init(void)
{
GRAPH *g = malloc(sizeof(*g));
memset(g,0,sizeof(*g));
return g;
}
void graph_config(GRAPH *g,GRAPH_NODE *start,GRAPH_NODE *end)
{
start->info.cost = 0;
end->info.Dijkstra_done = R_TRUE;
g->start = start;
g->end = end;
return;
}
GRAPH_NODE* graph_add_node(GRAPH *g,char *name)
{
GRAPH_NODE *node = malloc(sizeof(*node));
memset(node,0,sizeof(*node));
node->name = name;
node->info.cost = NODE_COST_INF;
node->next = g->node_head;
g->node_head = node;
return node;
}
RV graph_add_neigh(GRAPH_NODE *node,GRAPH_NODE *neigh_node,int cost)
{
GRAPH_LINK *link = malloc(sizeof(*link));
link->neigh_node = neigh_node;
link->cost = cost;
link->next = node->neigh_link;
node->neigh_link = link;
return R_OK;
}
static GRAPH_ROUTE_LIST* graph_new_route_list(GRAPH *g)
{
GRAPH_ROUTE_LIST *route_list = malloc(sizeof(*route_list));
memset(route_list,0,sizeof(*route_list));
route_list->next = g->route_list_head;
g->route_list_head = route_list;
return route_list;
}
static void link_list_traverse(GRAPH *g,GRAPH_ROUTE_LIST *route_list,GRAPH_LINK *neigh_link)
{
GRAPH_ROUTE *route = route_list->route_head;
GRAPH_ROUTE_LIST *new_route_list = route_list;
int cost = route_list->cost;
while(neigh_link)
{
if(!route->link)
route->link = neigh_link;
else // new route list
{
new_route_list = graph_new_route_list(g);
new_route_list->route_head = malloc(sizeof(GRAPH_ROUTE));
memcpy(new_route_list->route_head,route,sizeof(*route));
new_route_list->cost = cost;
route = new_route_list->route_head;
route->link = neigh_link;
}
new_route_list->cost += neigh_link->cost;
node_traverse(g,new_route_list,neigh_link->neigh_node);
neigh_link = neigh_link->next;
}
return;
}
static void node_traverse(GRAPH *g,GRAPH_ROUTE_LIST *route_list,GRAPH_NODE *node)
{
if(!node)return;
GRAPH_ROUTE *new_route = malloc(sizeof(*new_route));
new_route->node = node;
new_route->next = route_list->route_head;
route_list->route_head = new_route;
link_list_traverse(g,route_list,node->neigh_link);
return;
}
void graph_traverse(GRAPH *g)
{
GRAPH_ROUTE_LIST *route_list = graph_new_route_list(g);
node_traverse(g,route_list,g->start);
return;
}
static void Dijkstra_neigh_update(GRAPH_NODE *node,GRAPH_NODE *neigh_node,int link_cost)
{
int new_cost = node->info.cost + link_cost;
if(new_cost < neigh_node->info.cost)
{
neigh_node->info.cost = new_cost;
neigh_node->info.parent = node;
printf("node %s cost updated to %d\n",neigh_node->name,new_cost);
}
return;
}
static void Dijkstra_neigh_traverse(GRAPH_NODE *node)
{
while(node->neigh_link)
{
GRAPH_NODE *neigh_node = node->neigh_link->neigh_node;
Dijkstra_neigh_update(node,neigh_node,node->neigh_link->cost);
node->neigh_link = node->neigh_link->next;
}
node->info.Dijkstra_done = R_TRUE;
printf("node %s done\n",node->name);
return;
}
static GRAPH_NODE* Dijkstra_find_next_node(GRAPH *g)
{
GRAPH_NODE *node = g->node_head;
GRAPH_NODE *node_least_cost = NULL;
int least_cost = NODE_COST_INF;
while(node)
{
if(!node->info.Dijkstra_done && node->info.cost < least_cost)
{
node_least_cost = node;
least_cost = node->info.cost;
printf("updated to node %s,cost=%d,done=%d\n",node_least_cost->name,least_cost,node->info.Dijkstra_done);
}
node = node->next;
}
if(node_least_cost)
printf("next node is %s,cost=%d\n",node_least_cost->name,least_cost);
return node_least_cost;
}
void graph_Dijkstra_traverse(GRAPH *g)
{
GRAPH_NODE *node = g->start;
while(node)
{
Dijkstra_neigh_traverse(node);
node = Dijkstra_find_next_node(g);
}
return;
}
void graph_Dijkstra_print(GRAPH *g)
{
GRAPH_NODE *node = g->node_head;
while(node)
{
printf(" node %s cost=%d\n",node->name,node->info.cost);
node = node->next;
}
printf("least cost path is:\n");
node = g->end;
while(node)
{
printf("node %s\n",node->name);
node = node->info.parent;
}
return;
}
graph_test.c 代码
/*最短 路径问题 MSP */
#include
#include
#include
#include
#include
#include "define.h"
#include "graph.h"
void graph_test_init(void)
{
GRAPH_NODE *R,*R1,*R2,*R12,*R21,*R22,*R123;
GRAPH *g = NULL;
g = graph_init();
R = graph_add_node(g,"R");
R1 = graph_add_node(g,"R1");
R2 = graph_add_node(g,"R2");
R12 = graph_add_node(g,"R12");
R21 = graph_add_node(g,"R21");
R22 = graph_add_node(g,"R22");
R123 = graph_add_node(g,"R123");
graph_add_neigh(R,R1,5);
graph_add_neigh(R,R2,6);
graph_add_neigh(R1,R12,3);
graph_add_neigh(R2,R21,4);
graph_add_neigh(R21,R12,5);
graph_add_neigh(R2,R22,6);
graph_add_neigh(R22,R12,2);
graph_add_neigh(R12,R123,4);
graph_config(g,R,R123);
//graph_traverse(g);
//graph_print(g);
graph_Dijkstra_traverse(g);
graph_Dijkstra_print(g);
return;
}