圖的Dijkstra算法的C語言實現

在圖的遍歷算法的基礎上我們可以來實現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 <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#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 <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#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;
}
 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章