【算法导论】24.3 Dijkstra算法

算法导论24.3章中算法的C++实现,代码如下:

/******************************************************************** 
* Copyright (C) 2012 Li Yachao 
* Contact: liyc7711(at)gmail.com 
* 
* Permission to use, copy, modify, and distribute this software for 
* any non-commercial purpose is hereby granted without fee, provided 
* that the above copyright notice appear in all copies and that both 
* that copyright notice.  
* It is provided "as is" without express or implied warranty.  
*********************************************************************/ 
#include <iostream>
using namespace std;

#define  N 5  /*顶点的数目*/
#define INFINITE 0x7fffffff

//顶点结点结构  
struct Vertex  
{  
	Vertex * next;/*指向下一个顶点*/
	int id;/*节点的标志*/
	int weight;/*节点的权值,临界表表头到此元素上边的权值*/
    Vertex():next(NULL),id(0){}  
};  

//图结构
struct Graph
{
	Vertex *Adj[N+1];//N个顶点及邻接点头指针
	int p[N+1];//指向遍历树节点的父结点 
	int d[N+1];/*节点的最短路径权值的上界*/
	bool s[N+1];/*当前节点是否访问过*/
	Graph()
	{ 
        for(int i = 1; i <= N; i++)  
		{
            Adj[i] = new Vertex;
			d[i] = 0;
			p[i] = 0;
			s[i] = false;
		}
	}
	~Graph()  
    {  
        for(int i = 1; i <= N; i++)  
            delete Adj[i];  
    }  
};
/******最小优先级队列实现***************************************/
int Tail = 0;  
std::pair<int,int>  PriorStack[N+1];  
bool Push(std::pair<int,int>p);  
void PrintList();  
bool inline Exchange(int index1,int index2);  
bool inline Clear(int index);  
int Pop();  

/******算法实现***************************************/
void Print(Graph *g);
bool Init(Graph *g);
bool InsertEdge(Graph *g , int start,int end,int weight);
bool InitializeSingleSource(Graph *g,int s);
bool Relax(Graph *g,int u,int v,int weight);
bool Relax(Graph *g,int u,int v);
int  Weight(const Graph *g,int u,int v);
bool Dijkstra(Graph *g,int s);
int  ExtractMin(Graph *g);
bool UpdateKey(Graph *g);
/******最小优先级队列实现***************************************/
void PrintList()  
{  
    for(int i=1;i<=Tail;i++)  
    {  
        std::cout<<PriorStack[i].first<<"\t";  
    }  
    std::cout<<std::endl ;  
}  
/*向优先级队列插入元素,最大的元素在队列首部*/  
bool Push(std::pair<int,int>p)  
{  
    if(Tail >= N)  
    {  
        return false;/*溢出*/  
    }  
    Tail ++;  
    PriorStack[Tail] = p;  
    int cur = Tail/2;  
    if(cur < 1)  
    {  
        return true;  
    }  
	int t = Tail;
    while(true)  
    {/*依次于其父节点比较,如果小于则交换元素*/  
        if(PriorStack[t].second < PriorStack[cur].second)  
        {  
            Exchange(t,cur);  
        }  
		t = cur;
        cur = cur/2;
        if(cur == 0)  
        {  
            break;  
        }  
    }  
}  
/*弹出优先级最高的元素,一般为最大值*/  
int Pop()  
{  
    if(Tail < 1)  
    {  
        return -1;  
    }  
    int val = PriorStack[1].first;  
    Exchange(1,Tail);/*尾部元素与首部元素交换*/  
    Clear(Tail);  
    Tail --;  
    int p = 1;  
    int cur = 2*p;  
    while(true)  
    {/*如果父节点元素小于子节点元素则予以交换*/  
        if(PriorStack[p].second > PriorStack[cur].second)  
        {  
            Exchange(p,cur);  
        }  
        p = cur;  
        cur = p *2;  
        if(p >= Tail)  
        {  
            break;  
        }  
    }  
    return val;  
}  
/*交换两个位置上的元素*/  
bool inline Exchange(int index1,int index2)  
{  
    std::pair<int,int> tmp = PriorStack[index2];  
    PriorStack[index2] = PriorStack[index1];  
    PriorStack[index1] =tmp;  
    return true;  
}  
/*清空某个位置的元素*/  
bool inline Clear(int index)  
{  
    PriorStack[index].first = 0;  
    return true;  
}  
/*清空最小优先级队列*/
bool Clear()
{
	int Tail = 0;
	return true;
}
/******end最小优先级队列实现***************************************/
/*
start边开始节点,end边结束节点,weight边权值
*/
//插入边
bool InsertEdge(Graph *g , int start,int end,int weight)
{
	Vertex* v = new Vertex();
	v->id = end;
	v->weight = weight;
	if(g->Adj[start]->next == NULL)
	{/*如果不存在临界表的头结点列表中,则插入*/
		Vertex* s = new Vertex();
		s->id = start;
		g->Adj[start] = s;
	}
	Vertex* tmp = g->Adj[start];
	while(tmp->next)
	{
		tmp = tmp->next;
	}
	tmp->next =v;
	return true;
}

/*初始化邻接表表示的图,有向图。
*/
bool Init(Graph *g)
{
	InsertEdge(g,1,2,10);
	InsertEdge(g,1,4,5);
	InsertEdge(g,2,3,1);
	InsertEdge(g,2,4,2);
	InsertEdge(g,3,5,4);
	InsertEdge(g,4,2,3);
	InsertEdge(g,4,3,9);
	InsertEdge(g,4,5,2);
	InsertEdge(g,5,1,7);
	InsertEdge(g,5,3,6);
	return true;
}

/*取得两个两个节点连接的边的权重*/
int Weight(const Graph *g,int u,int v)
{
	Vertex * t = g->Adj[u]->next;
	while(t)
	{
		if(t->id == v)
		{
			return t->weight;
		}
		t = t->next;
	}
	return 0;
}
bool Relax(Graph *g,int u,int v,int weight)
{
	if(g->d[v] > (g->d[u] + Weight(g,u,v)))
	{
		g->d[v] = g->d[u] + Weight(g,u,v);
		g->p[v] = u;
	}
	return true;
}
/*对边进行松弛操作*/
bool Relax(Graph *g,int u,int v)
{
	Relax(g,u,v,Weight(g,u,v));
	return false;
}
/*
最短路径估计和前驱化进行初始化
s 源顶点
*/
bool InitializeSingleSource(Graph *g,int s)
{
	for(int i=1;i<=N;i++)
	{
		g->d[i] = INFINITE;
		g->p[i] = 0;
	}
	g->d[s] = 0;
	return true;
}
/*抽取顶点的路径权值最小的节点*/
int ExtractMin(Graph *g)
{
	UpdateKey(g);
	return Pop();
}
/*更新顶点的最小优先级队列*/
bool UpdateKey(Graph *g)
{
	Clear();
	for(int i=1;i<=N;i++ )
	{
		if(g->s[i] != true)
		{
			Push(std::make_pair<int,int>(i,g->d[i]));
		}
	}
	return true;
}
/*单源最短路径的Dijkstra算法*/
bool Dijkstra(Graph *g,int s)
{
	InitializeSingleSource(g,s);
	int vertex = ExtractMin(g);
	while(vertex >= 0)
	{
		g->s[vertex] = true;
		Vertex * t = g->Adj[vertex]->next;
		while(t)
		{
			Relax(g,vertex,t->id);
			t = t->next;
		}
		vertex = ExtractMin(g);
	}
	return true;
}
/*
开始顶点 1
顶点  最短路径
1       0
2       8
3       9
4       5
5       7
*/
int main(int argc,char * argv[])
{
	Graph *g = new Graph;
	Init(g);
	Dijkstra(g,1);
	for(int i=1;i<=N;i++)
	{
		std::cout<<i<<"\t"<<g->d[i]<<std::endl;
	}
	delete g;
	getchar();
	return 0;
}

    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/harry_lyc/article/details/8200164
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞