您的位置:首页 > 其它

单源最短路径-Dijkstra算法

2016-07-10 14:34 531 查看
Dijkstra算法求解单源最短路径比Bellman-Ford算法更加高效,但是缺陷是图中不能有权值为负数的边。

本代码中为了实现Dijstra算法使用到的数据结构或算法有:最小堆排序、松弛算法、贪心算法、有向图

保存此有向图的文件MapInfo.txt的内容如下:

s 10 t

s 5 y

t 1 x

t 2 y

y 3 t

y 9 x

y 2 z

x 4 z

z 6 x

z 7 s

左右两边的字符是节点名,中间的数字是两个节点所在边的权值。

具体代码实现如下:

/*
* 单源最短路径_Dijkstra算法
* 用到的算法或数据结构有:最小堆排序  松弛算法  贪心算法  有向图
*           author: StoryMonster
* Last Change Date: 2016/7/1
*/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

#ifndef TOTAL_NODES_IN_MAP
#define TOTAL_NODES_IN_MAP 5
#endif

#define MAX_DEEP    10000

enum {White,Grey,Black};

typedef struct MapNode
{
int deep;
char name;
int color;
} MapNode;
typedef struct MinPeal
{
MapNode *node;
int index;
struct MinPeal *father;
struct MinPeal *left;
struct MinPeal *right;
} MinPeal;
typedef struct NeiborTable
{
MapNode * node;
int weight;
struct NeiborTable *next;
} NeiborTable;

NeiborTable *Head[TOTAL_NODES_IN_MAP];
MinPeal *PealRoot = (MinPeal *)malloc(sizeof(PealRoot));
int PealNodeCount = 0;

static void     InitHeads();
static void     ReadConfigFile();
static void     InsertToNeiborTable(MapNode *,MapNode *,int);
static void     ShowNeiborTable();
static void     PutAllNodesToMinPeal();
static void     InsertToPeal(MinPeal *,MinPeal *);
static void     GetTheMinNode(MinPeal *,MinPeal *);
static MinPeal *GetMaxIndexPealNode(MinPeal *);
static void     FixThePeal(MinPeal *);
static void     Dijkstra(char NodeName);
static NeiborTable *GetNeiborNode(char);
static bool     AllNodesAreBlack();
static void     ShowShortestDistace();

void ShowShortestDistance(void)
{
for(int i=0;i < TOTAL_NODES_IN_MAP;i++)
{
std::cout << (Head[i]->node)->name << ":"<< (Head[i]->node)->deep<<std::endl;
}
}
NeiborTable *GetNeiborNode(char name)
{
for(int i=0;i < TOTAL_NODES_IN_MAP; i++)
{
if(name == (Head[i]->node)->name)
{
return Head[i];
}
}
return NULL;
}
bool AllNodesAreBlack(void)
{
for(int i=0;i<TOTAL_NODES_IN_MAP;i++)
{
if((Head[i]->node)->color != Black)
return false;
}
return true;
}
void DeepAll(char name , int deep)
{
for(int i=0;i<TOTAL_NODES_IN_MAP;i++)
{
NeiborTable *p = Head[i];
while(p != NULL)
{
if((p->node)->name == name)
{
(p->node)->deep = deep;
}
p = p->next;
}
}
}
void ColorAll(char name, int color)
{
for(int i=0;i < TOTAL_NODES_IN_MAP;i++)
{
NeiborTable *p = Head[i];
while(p != NULL)
{
if((p->node)->name == name)
{
(p->node)->color = color;
}
p = p->next;
}
}
}
void Dijkstra(char NodeName)
{
NeiborTable *p = GetNeiborNode(NodeName);
(p->node)->color = Grey;
(p->node)->deep  = 0;
ColorAll(NodeName,Grey);
DeepAll((p->node)->name,0);
FixThePeal(PealRoot);
while(!AllNodesAreBlack())
{
MinPeal *p3 = (MinPeal *)malloc(sizeof(MinPeal));
GetTheMinNode(PealRoot,p3);
if(p3 == NULL) break;
NeiborTable *p1 = GetNeiborNode((p3->node)->name);
NeiborTable *p2 = p1->next;
(p1->node)->color = Grey;
ColorAll((p1->node)->name,Grey);
while(p2 != NULL)
{
if((p2->node)->color == White)
{
if((p2->node)->deep > ((p1->node)->deep)+(p2->weight))
{
(p2->node)->deep = (p1->node)->deep + p2->weight;
//(p2->node)->color = Grey;
DeepAll((p2->node)->name,(p2->node)->deep);
//ColorAll((p2->node)->name,Grey);
}
}
p2 = p2->next;
}
(p1->node)->color = Black;
ColorAll((p1->node)->name,Black);
FixThePeal(PealRoot);
}
}

MinPeal *GetMaxIndexPealNode(MinPeal *root)
{
if(root == NULL) return NULL;
if(root->index == PealNodeCount) return root;
MinPeal *result = GetMaxIndexPealNode(root->left);
if(result == NULL) result = GetMaxIndexPealNode(root->right);
return result;
}
void FixThePeal(MinPeal *root)
{
if(root->left == NULL) return ;
if(((root->left)->node)->deep < (root->node)->deep)
{
MapNode *temp = (root->left)->node;
(root->left)->node = root->node;
root->node = temp;
if(root->father!=NULL ) FixThePeal(root->father);
else FixThePeal(root->left);
}
if(root->right == NULL) return ;
if(((root->right)->node)->deep < (root->node)->deep)
{
MapNode *temp = (root->right)->node;
(root->right)->node = root->node;
root->node = temp;
if(root->father!=NULL ) FixThePeal(root->father);
else FixThePeal(root->right);
}
}
void GetTheMinNode(MinPeal *root, MinPeal *node)
{
node->node = root->node;
node->father = NULL;
node->left = NULL;
node->right=  NULL;
MinPeal *p = GetMaxIndexPealNode(root);
root->node = p->node;
if(p == root)
{
free(p);
p = NULL;
root = NULL;
PealNodeCount--;
return ;
}
if((p->father)->left == p) (p->father)->left = NULL;
else (p->father)->right = NULL;
p->father = NULL;
free(p);
p = NULL;
PealNodeCount--;
FixThePeal(root);
}
void InsertToPeal(MinPeal *root,MinPeal *node)
{
if(PealRoot== NULL)
{
PealRoot = node;
return ;
}
if(root ==  NULL) return ;
if(node->index == 2*(root->index))
{
root->left = node;
node->father = root;
return ;
}
if(node->index == 2*(root->index)+1)
{
root->right = node;
node->father = root;
return ;
}
InsertToPeal(root->left,node);
InsertToPeal(root->right,node);
}
void PutAllNodesToMinPeal(void)
{
for(int i=0;i < TOTAL_NODES_IN_MAP;i++)
{
MinPeal *p = (MinPeal *)malloc(sizeof(MinPeal));
p->father = NULL;
p->left   = NULL;
p->right  = NULL;
p->index  = i+1;
p->node   = Head[i]->node;
InsertToPeal(PealRoot,p);
PealNodeCount++;
}
}
void ShowNeiborTable(void)
{
std::cout << "neibor table:"<<std::endl;
for(int i=0;i<TOTAL_NODES_IN_MAP;i++)
{
NeiborTable *p = Head[i];
while(p != NULL)
{
std::cout << (p->node)->name <<":" << p->weight<< "  ";
p = p->next;
}
std::cout << std::endl;
}
std::cout << "------------------------------" << std::endl;
}
void InsertToNeiborTable(MapNode *head, MapNode *node, int weight)
{
NeiborTable *p = (NeiborTable *)malloc(sizeof(NeiborTable));
p->weight = weight;
p->node = node;
for(int i=0;i<TOTAL_NODES_IN_MAP;i++)
{
if(Head[i] == NULL)
{
NeiborTable *pp = (NeiborTable *)malloc(sizeof(NeiborTable));
pp->node = head;
pp->weight = 0;
pp->next = NULL;
Head[i] = pp;
Head[i]->next = p;
return ;
}
else
{
if((Head[i]->node)->name == head->name)
{
NeiborTable *pp = Head[i];
while(pp->next != NULL) pp = pp->next;
pp->next = p;
return ;
}
}
}
}
void ReadConfigFile()
{
FILE *fp = fopen("MapInfo.txt","rb");
if(!fp)
{
std::cout <<"Open MapInfo.txt fail"<<std::endl;
fp = NULL;
return ;
}
while(1)
{
int weight = 0;
char name1 = 0,name2 = 0;
int n = fscanf(fp,"%c %d %c\n",&name1, &weight, &name2);
if(n < 1) break;
MapNode *node1 = (MapNode *)malloc(sizeof(MapNode));
MapNode *node2 = (MapNode *)malloc(sizeof(MapNode));
node1->name = name1;
node1->color = White;
node1->deep = MAX_DEEP;
node2->name = name2;
node2->color = White;
node2->deep = MAX_DEEP;
InsertToNeiborTable(node1,node2,weight);
}
fclose(fp);
fp = NULL;
}
void InitHeads(void)
{
for(int i=0;i < TOTAL_NODES_IN_MAP;i++)
{
Head[i] = NULL;
}
}
int main()
{
PealRoot = NULL;
InitHeads();
ReadConfigFile();
ShowNeiborTable();
PutAllNodesToMinPeal();
Dijkstra('s');
ShowShortestDistance();
return 0;
}


这里纠正一个错误,堆的英文是Heal,我一直记成了Peal,导致整篇代码中到处都是Peal。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息