Dijkstra算法介绍及其优先队列优化和斐波那契堆优化

Dijkstra算法介绍及其优先队列优化和斐波那契堆优化



一、dijkstra算法概述

  • Dijkstra算法解决的是带权重的有向图上单源最短路径问题,使用此算法的前提条件是所有边的权重都为非负值。
  • 算法重复从节点集中选择最短路径估计估计最小的节点u,然后对所有从u发出的边进行松弛(更新节点u的所有子节点到节点u的距离)。

二、实现dijkstra算法需要掌握的算法知识

1、从数据中剔除最小项(函数ExtractMin())

  1. 如果只是处于练习的目的,可以通过遍历所有节点(通常可以将所有节点存储于链表中,链表关键字为与父节点间的距离,主要卫星数据是本节点名称,及本节点的所有子节点的名称和二者间的距离)找到与源节点相距最短的节点(源节点的距离初始化为0,其他节点距离初始化为max),删除并返回该节点。但是这样做及其耗费时间。

  2. 使用优先队列(二叉堆实现,在后面讲解)删除并返回一个节点,优先队列指的是某个节点的值至多与其父节点一样大。因此,堆中的最小元素存放在根节点中(A[1])。因此,我们只需将根节点作为返回值,并删除根节点即可。

  3. 使用斐波那契堆删除并返回一个节点,斐波那契堆含有一个指向具有最小关键字的指针,因此只需删除并返回该指针即可。

2、松弛操作

伪代码:

Relax(u,v,w)//u为节点v的父节点
{
	if v.d>u.d+w(u,v)//w(u,v)表示从节点u到节点v的距离
		v.d=u.d+w(u,v)//更新子节点距离
		v.Π=u//将节点u最为节点v的新的父节点,属性Π表示v的父节点,本人代码使用f_dis、f_time、或father表示
}

松弛操作对应优先队列和斐波那契堆中的关键字减值。

3、伪代码分析

实现Dijkstra的伪代码:

Dij(G,w,s)//G表示所有节点的集合,s表示源节点
	Q=G.V//使用一个最小优先队列保存节点(基于二叉堆的优先队列或者斐波那契堆)
	while Q!=NIL //只有图中还有节点
		u=ExtractMin(Q)
		for each vertex v∈G.Adj[u]//对于节点u的每一个子节点
			Relax(u,v,w)//w表示一个属性,即节点u与节点v间的距离

可见,算法本身很简单,但其涉及的函数是比较难以用高效的方法实现的。

三、最小优先队列概述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

四、最小优先队列伪代码分析

1.维护堆的性质

在这里插入图片描述
图片中展示的是建立最大堆,建立最小堆需要改为:A[l]<A[i],以此类推。

2.建堆

在这里插入图片描述
所谓叶节点:就是下图中的节点8、7、6、9及其上面的节点。
在这里插入图片描述

3.剔除最小节点

ExtractMin(A)
	if A.heap-size<1//已经是空堆
		error "heap underflow"
	min=A[1]
	A[1]=A[A.heap-size]//这种直接赋值在实现中不可取,应该交换二者的值(地址)
	A.heap-size=A.heap-size-1//实现了删除一个节点
	MaxHeapIfy(A,1)
	return min

4.关键字减值(松弛操作,具体实现中将此函数命名为relax())

图片中描述的是最大堆的性质,类比即可。
在这里插入图片描述

HeapReduceKey(A,i,key)
	if key>A[i]
		error "new key is big than curren key"
	while i>and A[parent[i]]<A[i]
		exchange A[i] with A[parent[i]]
		i=parent[i];

五、例题分析

在这里插入图片描述

输入样例:

10 15
0 1 0 1 1
8 0 0 1 1
4 8 1 1 1
5 4 0 2 3
5 9 1 1 4
0 6 0 1 1
7 3 1 1 2
8 3 1 1 2
2 5 0 2 2
2 1 1 1 1
1 5 0 1 3
1 4 0 1 1
9 7 1 1 3
3 1 0 2 5
6 3 1 2 1
5 3

输出样例:

Time = 6: 5 => 4 => 8 => 3
Distance = 3: 5 => 1 => 3

1. 首先设法存储输入的数据

我们将所有节点数和道路条数分别记为all_pos、all_way,将起点和终点分别记为start、end。将道路信息存储至结构中。

typedef struct min{
	int pos;//本节点名称
	int son[3][1000];//子节点名称及属性,son[0][i]表示子节点名称,
	//对应的son[1][i]表示pos节点到son[0][i]节点的距离,son[2][i]表示对应时间
	int k;//子节点数目(松弛操作需要)
	int about_dis;//距离源节点可能的最小距离
	int about_time;
	int point;//根据题目表述建立的一个变量,表示节点个数
	struct min *f_time;
	struct min *f_dis;//父节点
}Min;

2. 设计最小优先队列

typedef struct heap{
	Min *A[1000];//用于存储节点
	int  sta[1000];//用于存储每一个关键字(节点名称)在数组A中的位置
	//如H->sta[key]表示关键字key在数组A中的位置,他是优化过程的核心。
	int heap_size;//数组A中符合优先队列的元素个数
	int length;//数组A的长度(为节约空间,应与all_pos一致)
}Heap;

3.实现Dijkstra算法(限于题目要求,略显臃肿)

/*dij*/
void dij(Heap *H,int opt)
{
	/*求距离*/ 
	if(opt==1)
	{
		while(!IsEmpty(H))
		{
			Min *u=ExtractMin(H,opt);
			for(int i=0;i<u->k;i++)
				relax(H,u,i,opt);
		}
	}
	/*求时间*/
	else
	{
		while(!IsEmpty(H))
		{
			Min *u=ExtractMin(H,opt);
			for(int i=0;i<u->k;i++)
				relax(H,u,i,opt);
		}
	}
}
Min *ExtractMin(Heap *H,int opt)
{
	if(opt==1)
	{
		Min *u=H->A[1];
		
		H->sta[H->A [1]->pos]=H->heap_size ;//更新关键字在数组A中的位置,关键操作。
		H->sta [H->A [H->heap_size ]->pos]=1;
		
		H->A [1]=H->A[H->heap_size ];
		H->A [H->heap_size ]=u;
		H->heap_size--;
		MaxHeapIfy(H,1,opt);
		return u;
	}
	else
	{
		Min *u=H->A[1];
		H->sta[H->A [1]->pos]=H->heap_size ;
		H->sta [H->A [H->heap_size ]->pos]=1;
		H->A [1]=H->A[H->heap_size ];
		H->A [H->heap_size ]=u;
		H->heap_size--;
		MaxHeapIfy(H,1,opt);
		return u;
	}
} 
void relax(Heap *H,Min *u,int p,int opt)
{
	Min *s=H->A[H->sta[u->son[0][p]]];
	int i=H->sta[u->son[0][p]];
	if(opt==1)
	{
		if(s->about_dis>(u->about_dis +u->son[1][p]))
		{
			s->f_dis =u;
			s->about_dis=u->about_dis +u->son[1][p];
			s->point=u->point+1;
			while((i>1)&&(H->A[i/2]->about_dis >H->A[i]->about_dis))
			{
				H->sta[H->A[i/2]->pos]=i;
				H->sta[H->A[i]->pos]=i/2;
				Min *temp=H->A[i/2];
				H->A[i/2]=H->A[i];
				H->A[i]=temp;
				i=i/2;
			}
		}
		else if((s->about_dis==(u->about_dis +u->son[1][p]))&&(s->point>=u->point+1))
		{
			s->f_dis =u;
			s->point=u->point+1;
			s->about_dis=u->about_dis +u->son[1][p];
			while((i>1)&&(H->A[i/2]->about_dis >H->A[i]->about_dis))
			{
				H->sta[H->A[i/2]->pos]=i;
				H->sta[H->A[i]->pos]=i/2;
				Min *temp=H->A[i/2];
				H->A[i/2]=H->A[i];
				H->A[i]=temp;
				i=i/2;
			}
		}
	}
	/*求时间*/
	else
	{
		if(s->about_time>(u->about_time+u->son[2][p]))
		{
			s->f_time=u;
			s->about_time=u->about_time+u->son[2][p];
			while((i>1)&&(H->A[i/2]->about_time>H->A[i]->about_time))
			{
				H->sta[H->A[i/2]->pos]=i;
				H->sta[H->A[i]->pos]=i/2;
				Min *temp=H->A[i/2];
				H->A[i/2]=H->A[i];
				H->A[i]=temp;
				i=i/2;
			}
		}
		else if((s->about_time==(u->about_time+u->son[2][p]))&&(s->about_dis>=(u->about_dis+u->son[1][p])))
		{
			s->f_time =u;
			s->about_time=u->about_time+u->son[2][p];
			while((i>1)&&(H->A[i/2]->about_time>H->A[i]->about_time))
			{
				H->sta[H->A[i/2]->pos]=i;
				H->sta[H->A[i]->pos]=i/2;
				Min *temp=H->A[i/2];
				H->A[i/2]=H->A[i];
				H->A[i]=temp;
				i=i/2;
			}
		}
	}
}
bool IsEmpty(Heap *H)
{
	if(H->heap_size ==0)
		return true;
	return false;
}

4.与优先队列有关的函数

/*与优先队列有关的函数*/
void BuildMinHeap(Heap *H,int opt)
{
	/*求距离*/
	if(opt==1)
	{
		H->heap_size=H->length;
		for(int i=H->length/2;i>=1;i--)
			MaxHeapIfy(H,i,opt);
	}
	/*求时间*/
	else
	{
		H->heap_size=H->length;
		for(int i=H->length/2;i>=1;i--)
			MaxHeapIfy(H,i,opt);
	}
}
void MaxHeapIfy(Heap *H,int i,int opt)
{
	/*求距离*/
	if(opt==1)
	{
		int l=2*i,r=2*i+1,min;
		if((l<=H->heap_size)&&(H->A[l]->about_dis<H->A[i]->about_dis))
			min=l;
		else
			min=i;
		if((r<=H->heap_size )&&(H->A [r]->about_dis<H->A[min]->about_dis))
			min=r;
		if(min!=i)
		{
			H->sta[H->A[min]->pos]=i;
			H->sta[H->A[i]->pos]=min;
			Min *temp=H->A[i];
			H->A[i]=H->A[min];
			H->A[min]=temp;
			MaxHeapIfy(H,min,opt);
		}	
	}
	/*求时间*/
	else
	{
		int l=2*i,r=2*i+1,min;
		if((l<=H->heap_size)&&(H->A[l]->about_time<H->A[i]->about_time))
			min=l;
		else
			min=i;
		if((r<=H->heap_size )&&(H->A [r]->about_time<H->A[min]->about_time))
			min=r;
		if(min!=i)
		{
			H->sta[H->A[min]->pos]=i;
			H->sta[H->A[i]->pos]=min;
			Min *temp=H->A[i];
			H->A[i]=H->A[min];
			H->A[min]=temp;
			MaxHeapIfy(H,min,opt);
		}
	} 
}
void InitializeHeap(Heap **H,int all_pos)
{
	if(*H==NULL)
		*H=(Heap *)malloc(sizeof(Heap));
	for(int i=1;i<=all_pos;i++)
	{
		(*H)->A[i]=(Min *)malloc(sizeof(Min));
		Min *u=(*H)->A[i];
		u->pos=i-1;
		(*H)->sta[u->pos]=i;
		u->about_time =u->about_dis =max;
		u->point=0;
		u->f_dis=u->f_time=NULL;
		u->k =0;
	}
	(*H)->heap_size=(*H)->length=all_pos;
}
void AddItem(Heap *H,Min item)
{
	
	Min *u=H->A[H->sta [item.pos]];
	u->son[0][u->k]=item.son[0][0];
	u->son[1][u->k]=item.son[1][0];
	u->son[2][u->k]=item.son[2][0];
	u->k++; 
} 

5.预处理信息、函数声明、主函数

nclude<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define max 1000000;
typedef struct min{
	int pos;
	int son[3][1000];
	int k;
	int about_dis;
	int about_time;
	int point;
	struct min *f_time;
	struct min *f_dis;
}Min;
typedef struct heap{
	Min *A[1000];
	int  sta[1000];
	int heap_size;
	int length;
}Heap;
void InitializeHeap(Heap **H,int all_pos);
void AddItem(Heap *H,Min item);
void dij(Heap *H,int opt);
void BuildMinHeap(Heap *H,int opt);
void MaxHeapIfy(Heap *H,int i,int opt);
void dij(Heap *H,int opt);
void relax(Heap *H,Min*u,int p,int opt);
Min *ExtractMin(Heap *H,int opt);
bool IsEmpty(Heap *H); 
int main(void)
{
	Heap *H=NULL;
	Min item;
	int i,j,argu;
	int all_pos,all_way,start,end;
	scanf("%d%d",&all_pos,&all_way);
	InitializeHeap(&H,all_pos);
	for(i=0;i<all_way;i++)
	{
		scanf("%d%d%d%d%d",&item.pos,&item.son[0][0],&argu,&item.son[1][0],&item.son[2][0]);
		AddItem(H,item);
		if(argu==0)
		{
			int temp=item.pos;
			item.pos=item.son[0][0];
			item.son[0][0]=temp;
			AddItem(H,item);
		}
	}
	scanf("%d%d",&start,&end);
	H->A[H->sta [start]]->about_dis=H->A[H->sta [start]]->about_time=0;
	H->A [H->sta[start]]->point=1;
	/*求距离*/ 
	BuildMinHeap(H,1);//1为距离,0为时间
	dij(H,1);
	/*将最短距离路径存入数组*/
	int dis[1000],k1=0,all_dis;
	Min *c=H->A[H->sta[end]];
	all_dis=c->about_dis;
	while(c->pos!=start)
	{
		dis[k1]=c->pos;
		k1++;
		c=c->f_dis;
		if(c==NULL)
		{
			all_dis=max;
			break;
		}
	}
	if(c!=NULL)
	{
		dis[k1]=start;
		k1++;
	}
	/*求时间*/
	/*重新初始化部分变量*/
	H->length=H->heap_size =all_pos;
	BuildMinHeap(H,0);
	dij(H,0);
	int time[1000],k2=0,all_time;
	c=H->A [H->sta[end]];
	all_time=c->about_time;
	while(c->pos!=start)
	{
		time[k2]=c->pos;
		k2++;
		c=c->f_time;
		if(c==NULL)
		{
			all_time=max;
			break;	
		}	
	} 
	if(c!=NULL)
	{
		time[k2]=start;
		k2++;
	}
	/*将结果输出*/
	bool arg=true;
	if(k1==k2)
	{
		for(i=0;i<k1;i++)
		{
			if(time[i]!=dis[i])
				arg=false;
		}
		if(arg)//距离和时间路线完全一致
		{
			printf("Time = %d; Distance = %d: %d",all_time,all_dis,dis[k1-1]);
			for(i=k1-2;i>=0;i--)
				printf(" => %d",dis[i]);	
		}
		else
		{
			printf("Time = %d: %d",all_time,time[k2-1]);
			for(i=k2-2;i>=0;i--)
				printf(" => %d",time[i]);
			printf("\nDistance = %d: %d",all_dis,dis[k1-1]);
			for(i=k1-2;i>=0;i--)
				printf(" => %d",dis[i]);
		}
	}
	else
	{
		printf("Time = %d: %d",all_time,time[k2-1]);
		for(i=k2-2;i>=0;i--)
			printf(" => %d",time[i]);
		printf("\nDistance = %d: %d",all_dis,dis[k1-1]);
		for(i=k1-2;i>=0;i--)
			printf(" => %d",dis[i]);
	}
	
}

6.不使用优先队列的实现

仅给出Dijkstra算法部分

/*dij函数部分*/
void dij(Min *head,int immi)
{
	Min *u;
	while(!IsEmpty(head))//运行时间Θ(n)
	{ 
		u=ExtractMin(head,immi);//至少(n^2)
		for(int i=0;i<u->k ;i++)
			relax(head,u,i,immi);
	} 
} 
//这个函数非常耗时
Min *ExtractMin(Min *head,int immi)
{
	Min *c=head,*u;
	int min;
	while(c!=NULL)
	{
		if(c->dele==false)
		{
			if(immi==0)
				min=c->about_time;
			else
				min=c->about_way;
			u=c;
			break;
		}
		c=c->next;
	}
	Min *c0=head;
	while(c0!=NULL)
	{
		if(immi==1)
		{
		
			if(c0->about_way <min&&c0->dele==false)
			{
				min=c0->about_way;
				u=c0;
			}
		}
		else
		{
			if(c0->about_time<min&&c0->dele==false)
			{
				min=c0->about_time;
				u=c0;
			}
		}
		c0=c0->next;
	}
	u->dele=true;
	return u;
} 
void relax(Min *head,Min *u,int pos,int immi)
{
	Min *c=head;
	while(c!=NULL)
	{
		if(c->pos==u->son[0][pos])
		{
			/*求最短距离*/
			if(immi==1)
			{
				if(c->about_way>(u->about_way +u->son[1][pos]))
				{
					c->about_way=u->about_way+u->son[1][pos];
					c->f_way =u;
					c->point =u->point+1;
				}
				else if((c->about_way==(u->about_way +u->son[1][pos]))&&(c->point>(u->point+1)))
				{
					c->about_way=u->about_way+u->son[1][pos];
					c->f_way =u;
					c->point =u->point+1;
				}
				break;
			}
			/*求最小时间*/
			else
			{
				if(c->about_time >(u->about_time +u->son[2][pos]))
				{
					c->about_time =u->about_time +u->son[2][pos];
					c->f_time =u;
				}
				else if((c->about_time ==(u->about_time +u->son[2][pos]))&&(c->about_way >(u->about_way +u->son[1][pos])))
				{
					c->about_time =u->about_time +u->son[2][pos];
					c->f_time =u;
				}
			} 
		}
		c=c->next;
	}
}
bool IsEmpty(Min *head)
{
	Min *c=head;
	while(c!=NULL)
	{
		if(c->dele==false)
			return false;
		c=c->next;
	}
	return true;
}

大致估计这种做法的运行时间达到Ω(n^3)。

六、斐波那契堆概述

在这里插入图片描述
字迹略显潦草。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

七、斐波那契堆伪代码分析

1.插入一个节点(插入到根链表)

/*我们可以利用插入节点操作建立一个由根链表的堆*/
FIB-HEAP-INSERT(H,x)
{
	x.degree=0
	x.p=NIL
	x.child=NIL
	x.mark=FALSE//这个属性不影响实现斐波那契堆的正确性,如果不理解为什么要添加此属性,那就不添加此属性。
	if H.min==NIL//根链表是空的(等价于堆为空)
		create a root list for H containng just x//创建一个只含x的堆
		H.min=x
	else insert x into H's root list //将x插入H的根链表,那么如何插入呢?
	/*我们可以给H两个属性,一个是根链表最左端的节点的地址,另一个是最右端节点的地址,
	然后只需按照个人爱好,将x与最左端或者最右段链接,然后分别更新最左、最右端节点的属性
	*/
		if x.key<H.min.key//更新最小节点
			H.min=x
	H.n=H.n+1
}

2.抽取最小节点

FIB-HEAP-EXTRACT-MIN(H)
z=H.min
if z≠NIL
	for each child x of z
		add x to the root list of
		x.p=NIL
	remove z from the root list of H
	if z==right
		H.min=NIL
	else H.min=z.right//随便选一个节点作为最小节点
		CONSOLIDATE(H)
	H.n=H.n-1
return z

3.合并H的根链表

CONSOLIDATE(H)
let A[0..D(H.n)] be a new array//A是指针数组
for i=0 to D(H.n)
	A[i]=NIL
for each node w in the root list of H//记为log
	x=w
	d=x.degree
	while A[d]≠NIL//如果此条件成立,说明此前根链表中有一个根与当前跟的孩子数目相同,符合条件进入循环
		y=A[d]
		if x.key>y.key//这一步是确保“将旧的链接到到新的上面”,假如将新发现的节点链接到到之前的节点上,
		//势必造成循环判断式log变得难以捉摸
			exchange x with y
		FIB-HEAP-LINK(H,y,x)
		A[d]=NIL//在以遍历的根节点中,子节点数目为d的节点已不复存在
		d=d+1
	A[d]=x//根节点x多了一个孩子y
	/*经过上面的操作得到了一个不知道最小关键字在何处的斐波那契堆*/
/*下面根据数组A重构斐波那契堆,找到最小关键字位置*/
H.min=NIL
for i=0 to D(H.n)
	if A[i]≠ NIL
		creat a root list for H containing just A[i]
		H.min=A[i]
	else insert A[i] into H's root list
		if A[i].key<H.min.key
			H.min=A[i]



/**/
FIB-HEAP-LINK(H,y,x)
remove y from the root list of H
make y a child of x,incrementing x.degree
y.mark=false//大家可以忽略此参数

4.关键字减值(relax())

FIB-HEAP-DECREASE-KEY(H,x,k)
if k>x.key
	error "new key is greater then current key"
x.key=k;
y=x.p
if y≠NIL and x.key<y.key//如果x不是根节点,且x的关键字比他的爸爸的关键字小,那么维护斐波那契堆的性质,x显然要不能继续当y的儿子了
	CUT(H,x,y)
	CASCADING-CUT(H,y)//这个函数的作用可能是防止某个根节点的层数太多,它本身完全不影响堆的正确性,大家可以忽略此函数
/*到此步后,无论x之前是不是根节点,他现在一定是根节点*/
if x.key<H.min.key
	H.min=x
/**/
CUT(H,x,y)
remove x from the child list of y,decrementing y.degree
add x to the root list of H
x.p=NIL
x.mark=FALSE

/**/
CASCADING-CUT(H,y)
z=y.p
if z≠NIL
	if y.mark==FALSE
		y.mark=TRUE
	else CUT(H,y,x)
		CASCADING-CUT(H,y)	

八.例题分析

针对上述例题,我们只考虑最短路径问题,不在讨论时间,同时忽略mark属性。

1.设法存储输入数据

typedef struct min{
	int pos;
	int son[3][1000];
	int k;//子节点个数 
	int about_dis;
	int about_time;
	int point;//限于题目要求添加的变量,记录节点个数 
	struct min *f_dis;
	struct min *f_time;
	/*构建堆的指针及参数(忽略mark属性)*/
	int degree;
	struct min *left;
	struct min *right;
	struct min *parent;
	struct min *child; 
}Min;

2.设计斐波那契堆

typedef struct fib{
	Min *min;
	int n;
	Min *sta[1000];//节点名称为下标,存储对应地址 
	Min *b_root_l;//最左端根链表的位置,专业名称叫哨兵 
	Min *b_root_r;
}Fib;

3.Dijkstra函数及相关函数


/*dij函数*/
void dij(Fib *H)
{
	Min *u;
	while(!IsEmpty(H))
	{
		u=ExtractMin(H);
		for(int i=0;i<u->k;i++)
			relax(H,u,i);
	}	
}

bool IsEmpty(Fib *H)
{
	if(H->min==NULL)
		return true;
	return false;	
}

Min *ExtractMin(Fib *H)
{
	//puts("Extract开始");
	Min *z=H->min;//因为要删除z,所以还要考虑z是不是最左/最右的根节点,更新哨兵 
	if(z!=NULL)
	{
	//	printf("将z(%d)的每一个孩子加入根链表:\n",z->pos);
		//for each child x of z
		/*先不去除z直接存储的那一个孩子,把他作为判断是否全部遍历z的孩子节点的标志*/
		if(z->child!=NULL)
		{
			Min *flag=z->child,*x=z->child->right;//先判断z有没有子节点
		//	printf("xf=%d\n",x->parent->pos);
			if(flag==x)//只有一个孩子节点 
				Addx(H,x);
			else
			{ 
				while(true)
				{	
					//printf("flag=%d\n",flag->pos);
					//printf("x(%d)的真正右兄弟:%d\n",x->pos,x->right->right->right ->pos); 
					Min *real_right=x->right;
					//将x加入根链表,这个操作建议写一个函数,虽然函数声明太多看起来有点不舒服
					 
					Addx(H,x);//第一次写:Addx(H,x)错误,z的孩子节点未更新 
					x->parent=NULL;
					
					x=real_right;//第一次写:此时x指向根节点,x的属性被更新了 
					
					//printf("x的实际:%d\n",x->pos); 
					if(x==flag)
					{
						Addx(H,x);	
						x->parent=NULL;
						z->child=NULL;
						break;
					} 
				}
			}
		
		}
		//remove z from the root list
		DeleteRootPoint(H,z); //易错
	}//结束将z的子节点加入根节点
	if(z==z->right)
		H->min=NULL;
	else
	{
		H->min=z->right;//随便找一个,下面的函数会找到一个正确的(在重新构成堆的时候)
		ConsoliDate(H);//易错 
	}
	H->n--;
	return z;//居然把这玩意忘了 
}


void relax(Fib *H,Min *u,int p)
{
	Min *x=H->sta[u->son[0][p]];
//	printf("实际:%d 理想:%d\n",x->pos,u->son[0][p]);
	if(x->about_dis>(u->about_dis+u->son[1][p]))
	{
		/*松弛操作*/ 
	//	printf("前:子节点%d距离=%d 现:父节点%d 距离:%d\n",x->pos,x->about_dis ,u->pos,u->about_dis+u->son[1][p]);
		x->f_dis=u;
		x->about_dis=u->about_dis+u->son[1][p];
		x->point=u->point+1;
		 
		/*堆操作*/
		Min *y=x->parent;
		if(y!=NULL&&x->about_dis<y->about_dis)//x的关键字减少之后要翻身做爸爸了 
			Cut(H,x,y);
		if(x->about_dis<H->min->about_dis)//H->min 为空 
			H->min=x;	
		//printf("relax():%d %d",H->min->pos,H->min->about_dis);
	}
	else if((x->about_dis==(u->about_dis+u->son[1][p]))&&(x->point>(u->point+1)))
	{
		
		/*松弛操作*/ 
		x->f_dis=u;
		x->about_dis=u->about_dis+u->son[1][p];
		x->point=u->point+1;
		/*堆操作*/
		Min *y=x->parent;
		if(y!=NULL&&x->about_dis<y->about_dis)//x的关键字减少之后要翻身做爸爸了 
			Cut(H,x,y);
		if(x->about_dis<H->min->about_dis)
			H->min=x;
			//	printf("relax():%d %d",H->min->pos,H->min->about_dis); 
	}
}

4.维护堆的函数


/*dij函数*/
void dij(Fib *H)
{
	Min *u;
	while(!IsEmpty(H))
	{
		u=ExtractMin(H);
		for(int i=0;i<u->k;i++)
			relax(H,u,i);
	}	
}

bool IsEmpty(Fib *H)
{
	if(H->min==NULL)
		return true;
	return false;	
}

Min *ExtractMin(Fib *H)
{
	//puts("Extract开始");
	Min *z=H->min;//因为要删除z,所以还要考虑z是不是最左/最右的根节点,更新哨兵 
	if(z!=NULL)
	{
	//	printf("将z(%d)的每一个孩子加入根链表:\n",z->pos);
		//for each child x of z
		/*先不去除z直接存储的那一个孩子,把他作为判断是否全部遍历z的孩子节点的标志*/
		if(z->child!=NULL)
		{
			Min *flag=z->child,*x=z->child->right;//先判断z有没有子节点
		//	printf("xf=%d\n",x->parent->pos);
			if(flag==x)//只有一个孩子节点 
				Addx(H,x);
			else
			{ 
				while(true)
				{	
					//printf("flag=%d\n",flag->pos);
					//printf("x(%d)的真正右兄弟:%d\n",x->pos,x->right->right->right ->pos); 
					Min *real_right=x->right;
					//将x加入根链表,这个操作建议写一个函数,虽然函数声明太多看起来有点不舒服
					 
					Addx(H,x);//第一次写:Addx(H,x)错误,z的孩子节点未更新 
					x->parent=NULL;
					
					x=real_right;//第一次写:此时x指向根节点,x的属性被更新了 
					
					//printf("x的实际:%d\n",x->pos); 
					if(x==flag)
					{
						Addx(H,x);	
						x->parent=NULL;
						z->child=NULL;
						break;
					} 
				}
			}
		
		}
		//remove z from the root list
		DeleteRootPoint(H,z); //易错
	}//结束将z的子节点加入根节点
	if(z==z->right)
		H->min=NULL;
	else
	{
		H->min=z->right;//随便找一个,下面的函数会找到一个正确的(在重新构成堆的时候)
		ConsoliDate(H);//易错 
	}
	H->n--;
	return z;//居然把这玩意忘了 
}


void relax(Fib *H,Min *u,int p)
{
	Min *x=H->sta[u->son[0][p]];
//	printf("实际:%d 理想:%d\n",x->pos,u->son[0][p]);
	if(x->about_dis>(u->about_dis+u->son[1][p]))
	{
		/*松弛操作*/ 
	//	printf("前:子节点%d距离=%d 现:父节点%d 距离:%d\n",x->pos,x->about_dis ,u->pos,u->about_dis+u->son[1][p]);
		x->f_dis=u;
		x->about_dis=u->about_dis+u->son[1][p];
		x->point=u->point+1;
		 
		/*堆操作*/
		Min *y=x->parent;
		if(y!=NULL&&x->about_dis<y->about_dis)//x的关键字减少之后要翻身做爸爸了 
			Cut(H,x,y);
		if(x->about_dis<H->min->about_dis)//H->min 为空 
			H->min=x;	
		//printf("relax():%d %d",H->min->pos,H->min->about_dis);
	}
	else if((x->about_dis==(u->about_dis+u->son[1][p]))&&(x->point>(u->point+1)))
	{
		
		/*松弛操作*/ 
		x->f_dis=u;
		x->about_dis=u->about_dis+u->son[1][p];
		x->point=u->point+1;
		/*堆操作*/
		Min *y=x->parent;
		if(y!=NULL&&x->about_dis<y->about_dis)//x的关键字减少之后要翻身做爸爸了 
			Cut(H,x,y);
		if(x->about_dis<H->min->about_dis)
			H->min=x;
			//	printf("relax():%d %d",H->min->pos,H->min->about_dis); 
	}
}

/*维护堆的函数*/
void Cut(Fib *H,Min *x,Min *y)//错 
{
	//remove x from the child list of y,decrmenting y.degree
	if(x==y->child)
	{
		if(x==x->right)
		{
			y->child=NULL; 
		}
		else
		{
			y->child=x->right;
			x->right->left=x->left;
			x->left->right=x->right; 
		} 
	}
	else
	{
		x->right->left=x->left;
		x->left->right=x->right; 
	}
	y->degree--;
	//add x to the root list of H
	H->b_root_r->left=x;
	H->b_root_l->right=x;
	x->left=H->b_root_r;
	x->right =H->b_root_l;
	H->b_root_r=x;
	x->parent=NULL;//勿漏 
	
}
void ConsoliDate(Fib *H)//易错函数 
{
	Min *A[H->n];//按理想状态,A的大小应该是根链表的数目
	for(int i=0;i<H->n;i++)
		A[i]=NULL;
	//for each node w in the root list of H
	//将根节点存入数组 ,在这个地方栽了 
	Min *root[H->n],*u=H->b_root_l;
	int k=0;
	while(u!=H->b_root_r)
	{
		root[k]=u;
		//printf("存储到根节点:%d \n",u->pos);
		u=u->right;
		k++;
	}
	root[k]=u;
	k++;
	
	
	//正式开始遍历每一个根节点 
	for(int i=0;i<k;i++)
	{
		Min *x=root[i];
		int d=x->degree;
		while(A[d]!=NULL)
		{
			Min *y=A[d];
			/*必须将旧的“位置”作为子节点链接到新的“位置”上,
			假如旧的节点比新的节点小,为了维护堆得性质,需要交换二者位置,让旧的变成新的*/
			if(x->about_dis>y->about_dis)
				//ecchange x with y
				Exchange(H,x,y);//易错
			FibHeapLink(H,y,x);//易错 	
			A[d]=NULL;//孩子个数为d节点不复存在
			d=d+1;
		}
		A[d]=x;//x多了一个子节点y ,开始把他写到while里面了 
	}
	
	/*根据A[i]重建堆并查找最小节点*/
 
	H->min=NULL;
	for(int i=0;i<H->n;i++)
	{
		if(A[i]!=NULL)
		{
			if(H->min==NULL)
			{
				//create a root list for H containg just A[i]
				A[i]->right=A[i]->left=A[i];
				A[i]->parent=NULL;
				H->b_root_l=H->b_root_r=A[i];
				//建好了
				H->min=A[i]; 
			}
			else
			{
				//insert A[i] into H's root list
				//和Addx()不同,插到最右边就行了,易错 
				H->b_root_r->left=A[i];
				H->b_root_l->right=A[i];
				A[i]->left=H->b_root_r;
				A[i]->right=H->b_root_l;
				H->b_root_r=A[i]; 
				 
				if(A[i]->about_dis<H->min->about_dis)
					H->min=A[i]; 
			}
		}	
	}
	if(H->min==NULL)
		printf("consil");
}


void FibHeapLink(Fib *H,Min *y,Min *x)//易错 
{
	//remove y from the root list of H
	DeleteRootPoint(H,y);
	//make y a child of x,incrememting x.degree
	if(x->child==NULL)
	{
		x->child=y;
		y->right=y->left=y;
		y->parent=x;
		x->degree++;	
	}
	else
	{
		//顺序可是很讲究的 
		x->child->right->left=y;
		y->right=x->child->right;
		
		x->child->right=y;
		y->left=x->child;
		y->parent=x;
		
		x->degree++;
	}
//	printf("y(%d)->parent=%d\n",y->pos,y->parent->pos);
	 
}
void FibHeapInsert(Fib *H,Min *x)//因为书上伪代码用的是x,我是更喜欢item的 
{
	x->degree=0;
	x->parent=NULL;//前面已经初始化过了,但是我就是想再来一遍,就是玩
	x->child=NULL;
	if(H->min==NULL)
	{
		//create a root list for H containing just x
		H->b_root_l=H->b_root_r =x;
		x->right=x->left=x;
		//这两行就建成了 
		H->min=x;	
	}
	else
	{
		//insert x into H's root list
		/*因个人喜好,我选择插到根链表的最右端,他和Addx()是不一样的*/
		H->b_root_r->right=x;
		H->b_root_l->left=x;
		x->right=H->b_root_l;
		x->left=H->b_root_r;
		H->b_root_r=x;
		//插完了 
		if(x->about_dis<H->min->about_dis)
			H->min=x;
	}
	H->n=H->n+1;
	
}

5.用户定义函数


/*dij函数*/
void dij(Fib *H)
{
	Min *u;
	while(!IsEmpty(H))
	{
		u=ExtractMin(H);
		for(int i=0;i<u->k;i++)
			relax(H,u,i);
	}	
}

bool IsEmpty(Fib *H)
{
	if(H->min==NULL)
		return true;
	return false;	
}

Min *ExtractMin(Fib *H)
{
	//puts("Extract开始");
	Min *z=H->min;//因为要删除z,所以还要考虑z是不是最左/最右的根节点,更新哨兵 
	if(z!=NULL)
	{
	//	printf("将z(%d)的每一个孩子加入根链表:\n",z->pos);
		//for each child x of z
		/*先不去除z直接存储的那一个孩子,把他作为判断是否全部遍历z的孩子节点的标志*/
		if(z->child!=NULL)
		{
			Min *flag=z->child,*x=z->child->right;//先判断z有没有子节点
		//	printf("xf=%d\n",x->parent->pos);
			if(flag==x)//只有一个孩子节点 
				Addx(H,x);
			else
			{ 
				while(true)
				{	
					//printf("flag=%d\n",flag->pos);
					//printf("x(%d)的真正右兄弟:%d\n",x->pos,x->right->right->right ->pos); 
					Min *real_right=x->right;
					//将x加入根链表,这个操作建议写一个函数,虽然函数声明太多看起来有点不舒服
					 
					Addx(H,x);//第一次写:Addx(H,x)错误,z的孩子节点未更新 
					x->parent=NULL;
					
					x=real_right;//第一次写:此时x指向根节点,x的属性被更新了 
					
					//printf("x的实际:%d\n",x->pos); 
					if(x==flag)
					{
						Addx(H,x);	
						x->parent=NULL;
						z->child=NULL;
						break;
					} 
				}
			}
		
		}
		//remove z from the root list
		DeleteRootPoint(H,z); //易错
	}//结束将z的子节点加入根节点
	if(z==z->right)
		H->min=NULL;
	else
	{
		H->min=z->right;//随便找一个,下面的函数会找到一个正确的(在重新构成堆的时候)
		ConsoliDate(H);//易错 
	}
	H->n--;
	return z;//居然把这玩意忘了 
}


void relax(Fib *H,Min *u,int p)
{
	Min *x=H->sta[u->son[0][p]];
//	printf("实际:%d 理想:%d\n",x->pos,u->son[0][p]);
	if(x->about_dis>(u->about_dis+u->son[1][p]))
	{
		/*松弛操作*/ 
	//	printf("前:子节点%d距离=%d 现:父节点%d 距离:%d\n",x->pos,x->about_dis ,u->pos,u->about_dis+u->son[1][p]);
		x->f_dis=u;
		x->about_dis=u->about_dis+u->son[1][p];
		x->point=u->point+1;
		 
		/*堆操作*/
		Min *y=x->parent;
		if(y!=NULL&&x->about_dis<y->about_dis)//x的关键字减少之后要翻身做爸爸了 
			Cut(H,x,y);
		if(x->about_dis<H->min->about_dis)//H->min 为空 
			H->min=x;	
		//printf("relax():%d %d",H->min->pos,H->min->about_dis);
	}
	else if((x->about_dis==(u->about_dis+u->son[1][p]))&&(x->point>(u->point+1)))
	{
		
		/*松弛操作*/ 
		x->f_dis=u;
		x->about_dis=u->about_dis+u->son[1][p];
		x->point=u->point+1;
		/*堆操作*/
		Min *y=x->parent;
		if(y!=NULL&&x->about_dis<y->about_dis)//x的关键字减少之后要翻身做爸爸了 
			Cut(H,x,y);
		if(x->about_dis<H->min->about_dis)
			H->min=x;
			//	printf("relax():%d %d",H->min->pos,H->min->about_dis); 
	}
}

/*维护堆的函数*/
void Cut(Fib *H,Min *x,Min *y)//错 
{
	//remove x from the child list of y,decrmenting y.degree
	if(x==y->child)
	{
		if(x==x->right)
		{
			y->child=NULL; 
		}
		else
		{
			y->child=x->right;
			x->right->left=x->left;
			x->left->right=x->right; 
		} 
	}
	else
	{
		x->right->left=x->left;
		x->left->right=x->right; 
	}
	y->degree--;
	//add x to the root list of H
	H->b_root_r->left=x;
	H->b_root_l->right=x;
	x->left=H->b_root_r;
	x->right =H->b_root_l;
	H->b_root_r=x;
	x->parent=NULL;//勿漏 
	
}
void ConsoliDate(Fib *H)//易错函数 
{
	Min *A[H->n];//按理想状态,A的大小应该是根链表的数目
	for(int i=0;i<H->n;i++)
		A[i]=NULL;
	//for each node w in the root list of H
	//将根节点存入数组 ,在这个地方栽了 
	Min *root[H->n],*u=H->b_root_l;
	int k=0;
	while(u!=H->b_root_r)
	{
		root[k]=u;
		//printf("存储到根节点:%d \n",u->pos);
		u=u->right;
		k++;
	}
	root[k]=u;
	k++;
	
	
	//正式开始遍历每一个根节点 
	for(int i=0;i<k;i++)
	{
		Min *x=root[i];
		int d=x->degree;
		while(A[d]!=NULL)
		{
			Min *y=A[d];
			/*必须将旧的“位置”作为子节点链接到新的“位置”上,
			假如旧的节点比新的节点小,为了维护堆得性质,需要交换二者位置,让旧的变成新的*/
			if(x->about_dis>y->about_dis)
				//ecchange x with y
				Exchange(H,x,y);//易错
			FibHeapLink(H,y,x);//易错 	
			A[d]=NULL;//孩子个数为d节点不复存在
			d=d+1;
		}
		A[d]=x;//x多了一个子节点y ,开始把他写到while里面了 
	}
	
	/*根据A[i]重建堆并查找最小节点*/
 
	H->min=NULL;
	for(int i=0;i<H->n;i++)
	{
		if(A[i]!=NULL)
		{
			if(H->min==NULL)
			{
				//create a root list for H containg just A[i]
				A[i]->right=A[i]->left=A[i];
				A[i]->parent=NULL;
				H->b_root_l=H->b_root_r=A[i];
				//建好了
				H->min=A[i]; 
			}
			else
			{
				//insert A[i] into H's root list
				//和Addx()不同,插到最右边就行了,易错 
				H->b_root_r->left=A[i];
				H->b_root_l->right=A[i];
				A[i]->left=H->b_root_r;
				A[i]->right=H->b_root_l;
				H->b_root_r=A[i]; 
				 
				if(A[i]->about_dis<H->min->about_dis)
					H->min=A[i]; 
			}
		}	
	}
	if(H->min==NULL)
		printf("consil");
}


void FibHeapLink(Fib *H,Min *y,Min *x)//易错 
{
	//remove y from the root list of H
	DeleteRootPoint(H,y);
	//make y a child of x,incrememting x.degree
	if(x->child==NULL)
	{
		x->child=y;
		y->right=y->left=y;
		y->parent=x;
		x->degree++;	
	}
	else
	{
		//顺序可是很讲究的 
		x->child->right->left=y;
		y->right=x->child->right;
		
		x->child->right=y;
		y->left=x->child;
		y->parent=x;
		
		x->degree++;
	}
	if(H->min==NULL)
	printf("link");
//	printf("y(%d)->parent=%d\n",y->pos,y->parent->pos);
	 
}
void FibHeapInsert(Fib *H,Min *x)//因为书上伪代码用的是x,我是更喜欢item的 
{
	x->degree=0;
	x->parent=NULL;//前面已经初始化过了,但是我就是想再来一遍,就是玩
	x->child=NULL;
	if(H->min==NULL)
	{
		//create a root list for H containing just x
		H->b_root_l=H->b_root_r =x;
		x->right=x->left=x;
		//这两行就建成了 
		H->min=x;	
	}
	else
	{
		//insert x into H's root list
		/*因个人喜好,我选择插到根链表的最右端,他和Addx()是不一样的*/
		H->b_root_r->right=x;
		H->b_root_l->left=x;
		x->right=H->b_root_l;
		x->left=H->b_root_r;
		H->b_root_r=x;
		//插完了 
		if(x->about_dis<H->min->about_dis)
			H->min=x;
	}
	H->n=H->n+1;
	
}


/*用户定义函数*/ 
void Exchange(Fib *H,Min *x,Min *y)//易错函数
{
//	printf("前:x=%d y=%d\n",x->pos,y->pos);
	if(x==H->b_root_l&&y!=H->b_root_r)
	{
		x->left->right=y;
		x->right->left=y;
		
		y->left->right=x;
		y->right->left=x;
		
		H->b_root_l=y;
	}
	else if(x==H->b_root_r&&y!=H->b_root_l)
	{
		x->left->right=y;
		x->right->left=y;
		
		y->left->right=x;
		y->right->left=x;
		
		H->b_root_r=y;
	}
	else if(y==H->b_root_l&&x!=H->b_root_r)
	{
		x->left->right=y;
		x->right->left=y;
		
		y->left->right=x;
		y->right->left=x;
		
		H->b_root_l=x;
	}
	else if(y==H->b_root_r&&x!=H->b_root_l)
	{
		x->left->right=y;
		x->right->left=y;
		
		y->left->right=x;
		y->right->left=x;
		
		H->b_root_r=x;
	}
	else if(x==H->b_root_l&&y==H->b_root_r)
	{
		x->left->right=y;
		x->right->left=y;
		
		y->left->right=x;
		y->right->left=x;
		
		H->b_root_l=y;
		H->b_root_r=x;
	}
	else if(x==H->b_root_r&&y==H->b_root_l)
	{
		x->left->right=y;
		x->right->left=y;
		
		y->left->right=x;
		y->right->left=x;
		
		H->b_root_l=x;
		H->b_root_r=y;
	}
	else
	{
		x->left->right=y;
		x->right->left=y;
		
		y->left->right=x;
		y->right->left=x;
	}
//	printf("后:x=%d y=%d\n",x->pos,y->pos);
	
} 

void Addx(Fib *H,Min *x)//易错函数 
{
	/*更新根链表*/
	H->b_root_r->right=x;
	H->b_root_l->left=x;
	/*更新z的孩子*/
	Min *c_l=x->left,*c_r=x->right;//x作为z的孩子节点,x变为根节点的同时也需要更新z的孩子节点
	c_l->right=c_r;
	c_r->left=c_l;
//	printf("%d\n",x->parent->child);
	//printf("add:x->left=%d x->right=%d x->pos=%d z->c=%d\n",x->left->pos,x->right->pos,x->pos,x->parent->child->pos);
	/*更新x*/ 
	x->right=H->b_root_l;
	x->left=H->b_root_r;
	
	/*更新哨兵*/
	H->b_root_r=x;
	
	x->parent=NULL;//这一步尽量写着吧,虽然主调函数也写了,但是。。。 	
} 
void DeleteRootPoint(Fib *H,Min *z)//易错函数 
{
	if(z==H->b_root_l)
	{
		z->left->right=z->right;
		z->right->left=z->left;
		H->b_root_l=z->right;	
	}
	else if(z==H->b_root_r)
	{
		z->left->right=z->right;
		z->right->left=z->left;
		H->b_root_r=z->left;	
	}
	else
	{
		z->left->right=z->right;
		z->right->left=z->left;
	}
	
}

void Initialize(Fib **H,int all_pos)//容易出错的函数 
{
	if((*H)==NULL)
		*H=(Fib *)malloc(sizeof(Fib));
	(*H)->n=0;//易漏部分
	(*H)->min=(*H)->b_root_l=(*H)->b_root_r=NULL; 
	for(int i=0;i<all_pos;i++)
	{
		(*H)->sta[i]=(Min*)malloc(sizeof(Min));
		Min *u=(*H)->sta[i];
		/*易漏部分*/
		u->pos=i;
		u->about_dis=u->about_time=max;
		u->k=0;
		u->point=0;//源节点需要修改为1 
		u->f_dis=u->f_time=u->left=u->right=u->parent=u->child=NULL;
	}
	/*下面将各个节点加入堆中(将(*H)->sta[i]作为输入哟)*/
	for(int i=0;i<all_pos;i++)
		FibHeapInsert(*H,(*H)->sta[i]);	
}
void updata(Fib *H,Min item)
{
	Min *u=H->sta[item.pos];
	u->son[0][u->k]=item.son[0][0];
	u->son[1][u->k]=item.son[1][0];
	u->son[2][u->k]=item.son[2][0]; 
	u->k++;
}

6.预处理、声明、主函数

//易错:
//删除一个根节点要考虑他是否是最左或最右的根节点
//移动一个根节点至根节点要更新哨兵
//将某个孩子节点加入根节点要更新他的旧兄弟和新兄弟和哨兵 
//交换两个节点要考虑哨兵 
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define max 1000000;
typedef struct min{
	int pos;
	int son[3][1000];
	int k;//子节点个数 
	int about_dis;
	int about_time;
	int point;//限于题目要求添加的变量,记录节点个数 
	struct min *f_dis;
	struct min *f_time;
	/*构建堆的指针及参数(忽略mark属性)*/
	int degree;
	struct min *left;
	struct min *right;
	struct min *parent;
	struct min *child; 
}Min;
typedef struct fib{
	Min *min;
	int n;
	Min *sta[1000];//节点名称为下标,存储对应地址 
	Min *b_root_l;//最左端根链表的位置,专业名称叫哨兵 
	Min *b_root_r;
}Fib;
/*dij函数*/
void dij(Fib *H);
void relax(Fib *H,Min *u,int p);//维护堆的函数,关键字减值 
Min *ExtractMin(Fib *H);//维护堆的函数 ,去除并返回最小节点 
bool IsEmpty(Fib *H); 
/*维护堆的函数*/ 
void FibHeapInsert(Fib *H,Min *x);
void ConsoliDate(Fib *H);
void FibHeapLink(Fib *H,Min *y,Min *x);
void Cut(Fib *H,Min *x,Min *y);
/*用户定义函数*/
void Initialize(Fib **H,int all_pos);
void updata(Fib *H,Min item);
void Addx(Fib *H,Min *x);//针对的是y的子节点x 
void DeleteRootPoint(Fib *H,Min *z);
void Exchange(Fib *H,Min *x,Min *y); 
int main(void)
{
	Fib *H=NULL;//使用指针,为其分配空间,而不是直接建立变量的目的是节省时间和空间
	Min item;
	int i,j,all_pos,all_way,start,end,argu;
	scanf("%d%d",&all_pos,&all_way);
	Initialize(&H,all_pos);//我们将节点0~all_pos在这一步加入堆的根节点中,然后通过下面的updata()函数更新节点信息 
	for(i=0;i<all_way;i++)
	{
		scanf("%d%d%d%d%d",&item.pos,&item.son[0][0],&argu,&item.son[1][0],&item.son[2][0]);
		updata(H,item);
		if(argu==0)
		{
			int temp=item.pos;
			item.pos=item.son[0][0];
			item.son[0][0]=temp;
			updata(H,item);	
		}	
	}
	scanf("%d%d",&start,&end);
	H->sta[start]->about_dis =0;//不管时间了,只初始化距离相关的量 
	H->sta[start]->point=1;
	H->min=H->sta[start];
	dij(H);
	Min *c=H->sta [end];
	while(c->pos!=start)
	{
		printf("%d<=",c->pos);
		c=c->f_dis;
		if(c==NULL)
		{
			printf("无此路径!");
			exit(1);	
		} 
	}
	printf("%d\n",start);
}/*主函数结束*/

在这里插入图片描述

注意

ConsilDate()函数中遍历根节点我是用两个循环实现的,我想这不是一个好的实现,希望大神给出更好的方法。
注意:文中大部分介绍来自《算法导论》第三版

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值