dijkstra演算法筆記(C語言實現,顯示路徑)

brench11發表於2020-12-01

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)
最後的輸出結果:
在這裡插入圖片描述

相關文章