dijkstra算法(迪杰斯特拉算法)笔记(C语言实现,显示路径)
具体描述每一步的运行情况
在学习完广度优先搜索之后,了解了在无权图中怎么找出最短路径。但广度优先搜索解决不了当边具有权值的情况。
dijkstra算法就是解决这种情况的算法。
一个具有边权的图:
现在,以1位初始点,找出各点到1的最短距离,并且显示路径。
首先创建一个结构数组,来储存各点的信息:
struct item{
int key; //这个点是否被访问
int dis; //这个点到原点的距离
int n_number; //路径中有多少个点
int n[10]; //创建数组来储存路径
};
struct item dist[9]; //这个图中有9个点
从1开始,与1相连的2,8都没有被访问过,进入队列,并更新这些点的信息:
现在,队列头是2,于是2出队列,与2相关联且满足条件的进入队列(满足条件应分两种情况;1.若这个点没有被访问,直接进入队列。2.若这个点已经被访问,但新路径的距离比原路径的距离要短,这个点也入队,更新信息),更新各点的信息:
在上一步中,8虽然已经被访问过了,但更新之后8由路径(1-2-8)到1的距离为7,比之前的要小,所以点8的各项信息被更新,进入对列,所以现在队列中的(8,3,8)两个8具有一样的信息。
现在,与8相关的点进入队列,8出队列:更新后的信息:
继续操作,3出队,与3相关的点入队:
这里4,还没有被访问,直接入队,
9已经被访问,但9目前的距离为8,比12+2要小,9,不用入队。
现在,由于8已经被操作过,所以,8单纯出队,没有元素入队:
接着,7出队,6入队
接着,在9出队,且与9相连的点中,3满足更新条件(3目前距离为12,更新后为8+2=10),3入队:
4出队,5入队
至此所有元素都已经访问完毕,但队列并不为空,意味着仍然有元素可能会被更新
6出队,5满足更新条件,5入队
继续执行,3出队,4满足更新条件,入队:
接下来的两个5单纯出队,没有任何元素满足入队条件:
最后4出队,同样没有元素满足更新条件,没有元素入队,队列为空。算法结束。
最终结果如下:
代码与测试数据`
#include<stdlib.h>
#include<string.h>
#include<stdio.h>
struct node;
typedef struct node * pNode;
struct node{
int num;
int power;
pNode next;
};
struct item{
int key; //这个点是否被访问
int dis; //这个点到原点的距离
int n_number; //路径中有多少个点
int n[10]; //创建数组来储存路径
};
struct queue;
typedef struct queue * pQueue;
struct queue{
int num;
pQueue next;
};
pQueue add(pQueue,pQueue);
pQueue out(pQueue);
void show(pNode *,int);
int main()
{
pNode * list;
int a,b,c,N,i,j;
pNode current,temp;
scanf("%d",&N);
list=(pNode *)malloc(sizeof(pNode)*N);
for(i=0;i<N;i++){
list[i]=(pNode)malloc(sizeof(struct node));
temp=list[i];
temp->num=i+1;
temp->next=NULL;
while(scanf("%d",&a)==1){
current=(pNode)malloc(sizeof(struct node));
current->num=a;
scanf("%d",&b);
current->power=b;
current->next=NULL;
temp->next=current;
temp=current;
}
getchar();
}
show(list,N);
//储存完毕,开始搜索
struct item dist[N];
for(i=0;i<N;i++){
dist[i].key=0;
dist[i].dis=0;
dist[i].n_number=0;
}
//以第一个点为初始点
dist[0].key=1;
dist[0].dis=0;
int dis=0 ,count=1,x[10];
x[0]=1;
pQueue head=NULL,kong;
current=list[0]->next;
do{
while(current!=NULL){
if(dist[current->num-1].key==0){//第一次遇到,直接入队
dist[current->num-1].key=1;
dist[current->num-1].dis=dis+current->power;
kong=(pQueue)malloc(sizeof(struct queue));
kong->num=current->num;
head=add(head,kong);
//开始复制数组;
for(i=0;i<count;i++)
dist[current->num-1].n[i]=x[i];
dist[current->num-1].n[count]=current->num;
dist[current->num-1].n_number=count+1;
}
else if(dist[current->num-1].dis>dis+current->power){
dist[current->num-1].dis=dis+current->power;
kong=(pQueue)malloc(sizeof(struct queue));
kong->num=current->num;
head=add(head,kong);
//开始复制数组;
for(i=0;i<count;i++)
dist[current->num-1].n[i]=x[i];
dist[current->num-1].n[count]=current->num;
dist[current->num-1].n_number=count+1;
}
current=current->next;
}
current=list[head->num-1]->next;
count=dist[head->num-1].n_number;
for(i=0;i<count;i++)
x[i]=dist[head->num-1].n[i];
dis=dist[head->num-1].dis;
head=out(head);
while(current!=NULL){
if(dist[current->num-1].key==0){//第一次遇到,直接入队
dist[current->num-1].key=1;
dist[current->num-1].dis=dis+current->power;
kong=(pQueue)malloc(sizeof(struct queue));
kong->num=current->num;
head=add(head,kong);
//开始复制数组;
for(i=0;i<count;i++)
dist[current->num-1].n[i]=x[i];
dist[current->num-1].n[count]=current->num;
dist[current->num-1].n_number=count+1;
}
else if(dist[current->num-1].dis>dis+current->power){
dist[current->num-1].dis=dis+current->power;
kong=(pQueue)malloc(sizeof(struct queue));
kong->num=current->num;
head=add(head,kong);
//开始复制数组;
for(i=0;i<count;i++)
dist[current->num-1].n[i]=x[i];
dist[current->num-1].n[count]=current->num;
dist[current->num-1].n_number=count+1;
}
current=current->next;
}
}while(head!=NULL);
for(i=0;i<N;i++){
if(dist[i].dis==0){
printf("元素:%d 原点",i+1);
}
else{
printf("元素:%d 距离:%d",i+1,dist[i].dis);
printf(" 路径:");
for(j=0;j<dist[i].n_number;j++){
printf("%d--",dist[i].n[j]);
}
printf("\n");
}
}
}
void show(pNode *list,int N)
{
int i;
pNode current;
for(i=0;i<N;i++)
{
printf("%d -> ",list[i]->num);
current=list[i]->next;
while(current!=NULL){
printf("%d(%d) ",current->num,current->power);
current=current->next;
}
puts("");
}
}
pQueue out(pQueue head)
{
if(head->next==NULL){
free(head);
return NULL;
}
else{
pQueue temp=head->next;
free(head);
return temp;
}
}
pQueue add(pQueue head,pQueue current)
{
if(head==NULL){
head=current;
current->next=NULL;
}
else{
pQueue temp=head;
while(temp->next!=NULL)
temp=temp->next;
temp->next=current;
current->next=NULL;
}
return head;
}
测试数据:
9
2 4 8 8 +
1 4 8 3 3 8 +
2 8 9 2 4 7 +
3 7 6 14 5 9 +
4 9 6 10 +
4 14 5 10 7 2 +
6 2 9 6 8 6 +
7 6 9 1 2 3 1 8 +
3 2 7 6 8 1 +
以输入非数字符号结束,所以后面有一个加号
以散列表(那个形式,没有散列函数)储存图的结构:
1 -> :2(4) 8(8)
2 -> :1(4) 8(3) 3(8)
3 -> :2(8) 9(2) 4(7)
4 -> :3(7) 6(14) 5(9)
5 -> :4(9) 6(10)
6 -> :4(14) 5(10) 7(2)
7 -> :6(2) 9(6) 8(6)
8 -> :7(6) 9(1) 2(3) 1(8)
9 -> :3(2) 7(6) 8(1)
最后的输出结果: