1.實驗目的
(1)掌握圖的鄰接矩陣和鄰接表存儲方式;
(2)掌握圖的遍歷算法;
(3)掌握圖的實際應用——最短路徑算法。
2.實驗內容
(1)採用鄰接矩陣/鄰接表建立圖;
(2)採用深度優先/廣度優先搜索方式遍歷圖;
(3)編程實現Dijkstra最短路徑算法。
3.實驗步驟
- 編寫代碼,採用鄰接表法建立有向圖:
(1)輸入總邊數、總點數;
(2)依次輸入點的信息存入頂點表,使每個表頭結點的指針域初始化爲NULL;
(3)創建鄰接表,依次輸入每條邊依附的兩個頂點,以及邊的權值,確定這兩個定點的序號i和j後,將邊結點分別插入v_i和v_j對應的兩個邊鏈表的頭部。 - 編寫代碼,實現深度優先搜索方式遍歷圖:
(1)從圖中某個頂點v出發,訪問v,並設置visited[v]的值爲true;
(2)依次檢查v的所有鄰接點w,如果visited[w]的值爲false,再從w出發進行遞歸遍歷,直到圖中所有頂點都被訪問過。 - 編程實現Dijkstra最短路徑算法。
(1)初始化最短路徑數組D,將其賦值爲最大值10000;
(2)如果v0與vi之間有弧,則將他們的權值賦給D[i];
(3)初始化數組S,將源點v0加到S中,即S[v0] = true;
(4)選擇下一條最短路徑的終點vk,令S[k]=true;
(5)根據條件更新從v0到其他頂點的最短路徑的長度,若D[k]+p->info<D[p->adjvex],則令D[p->adjvex] = D[k]+p->info。
4.實驗代碼
#include <iostream>
#include <iomanip>
using namespace std;
#define MVNum 100
bool visited[100] = {false};
//有向圖的鄰接表存儲表示 95
typedef int OtherInfo;
typedef char VerTexType;
//邊結點
typedef struct ArcNode
{
int adjvex; //該邊指向的頂點的位置
struct ArcNode *nextarc; //指向下一條邊的指針
OtherInfo info; //權值
}ArcNode;
//頂點信息
typedef struct VNode
{
VerTexType data; //頂點的值
ArcNode *firstarc; //指向第一條依附該頂點的邊的指針
}VNode,AdjList[MVNum];
//鄰接表
typedef struct
{
AdjList vertices;
int vexnum,arcnum; //圖的頂點數,邊數
}ALGraph;
//確定定點u在圖中的位置
int LocateVex(ALGraph G,VerTexType u);
//創建有向圖
void CreateDG(ALGraph &G);
//深度優先遍歷
void DFS_AL(ALGraph G,int v);
//Dijkstra算法
void ShortestPath_DIJ(ALGraph G,int v0);
int main()
{
int v0;
VerTexType data;
ALGraph G;
CreateDG(G);
cout << "請輸入v0的值:" ;
cin >> data;
v0 = LocateVex(G,data);
cout << "深度優先遍歷後得到的頂點順序爲:";
DFS_AL(G,v0);
cout << endl;
cout << "請輸入v0的值:" ;
cin >> data;
v0 = LocateVex(G,data);
ShortestPath_DIJ(G,v0);
return 0;
}
int LocateVex(ALGraph G,VerTexType u)
{
//若G中存在頂點u,則返回該頂點的位置,否則返回-1.
for(int i=0;i<G.vexnum;++i)
if(u == G.vertices[i].data)
return i;
return -1;
}
void CreateDG(ALGraph &G)
{
VerTexType v1,v2;
OtherInfo otherInfo;
//VerTexType ch[8] = "abcdefg";
//VerTexType ch1[12] = "aaabcceffgd";
//VerTexType ch2[12] = "bcdeefggdbg";
//OtherInfo oi[11] = {15,2,12,6,8,4,9,10,5,4,3};
int j,k;
cout << "請輸入圖的總邊數,總點數:";
cin >> G.arcnum >> G.vexnum;
//G.arcnum = 11;
//G.vexnum = 7;
cout << "請輸入頂點的值:";
//表頭結點
for(int i=0;i<G.vexnum;++i)
{
//G.vertices[i].data = ch[i];
cin >> G.vertices[i].data;
G.vertices[i].firstarc = NULL;
}
cout << "請輸入一條邊依附的兩個頂點以及邊的權值:";
//邊結點
for(int i=0;i<G.arcnum;++i)
{
cin >> v1 >> v2 >> otherInfo;
//v1 = ch1[i];v2 = ch2[i];otherInfo = oi[i];
j = LocateVex(G,v1);
k = LocateVex(G,v2);
ArcNode* p1 = new ArcNode;
p1->adjvex = k;
p1->info = otherInfo;
p1->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p1;
}
}
void DFS_AL(ALGraph G,int v)
{
int w;
cout << v << ":" << G.vertices[v].data << " ";
visited[v] = true;
ArcNode* p = G.vertices[v].firstarc;
while(p != NULL)
{
w = p->adjvex;
if(!visited[w])
DFS_AL(G,w);
p = p->nextarc;
}
}
void ShortestPath_DIJ(ALGraph G,int v0)
{
int n = G.vexnum,k;
bool S[n] = {false};
OtherInfo D[n],Min;
int Path[n];
ArcNode* p;
//初始化最短路徑的值
for(int v=0;v<n;++v)
D[v] = 10000;
p = G.vertices[v0].firstarc;
//將與v0相關聯的邊的權值賦給D[]
while(p != NULL)
{
D[p->adjvex] = p->info;
p = p->nextarc;
}
S[v0] = true; //將v0加入終點集
Path[0] = v0; //記錄最短路徑
D[v0] = 0;
for(int v=1;v<n;++v)
{
Min = 10000;
//尋找最小值
for(int w=0;w<n;++w)
{
if(!S[w] && D[w]<Min)
{
k = w;
Min = D[w];
}
}
S[k] = true;
Path[v] = k;
p = G.vertices[k].firstarc;
while(p != NULL)
{
if(!S[p->adjvex] && D[k]+p->info<D[p->adjvex])
D[p->adjvex] = D[k]+p->info;
p = p->nextarc;
}
}
for(int i=1;i<n;i++)
{
cout << "終點集爲:";
for(int j=0;j<=i;j++)
cout << G.vertices[Path[j]].data;
cout << setw(15) << "最短路徑值爲:" << D[Path[i]] << endl;
}
}
5.實驗總結
(1)鄰接矩陣法適合建立稠密圖;鄰接表法適合建立稀疏圖。
(2)深度優先搜索遍歷類似於樹的先序遍歷,藉助於棧結構來實現遞歸;廣度優先搜索遍歷類似於樹的層次遍歷,藉助於隊列結構來實現。
(3)Dijkstra算法求最短路徑求解過程是,按照路徑長度遞增的次序產生最短路徑,時間複雜度是O(n^2)。
數據結構核心原理與算法應用