圖的遍歷(深度優先遍歷)
阿新 • • 發佈:2018-12-15
首先來講一下資料結構中圖的基本概念:
什麼是圖結構:
圖資料結構是每個資料元素之間可以任意關聯,構成了圖結構。正是這種任意關聯性,導致圖結構中的資料關係的複雜性。
典型的圖結構包含兩個部分:
頂點(vertex): 圖中的資料元素。
邊(Edge):圖中連線這些頂點的線。
所有的頂點構成一個頂點集合,所有邊構成邊集合,圖結構就是由頂點集合和邊集合組成。
無向圖:
每條邊都沒有方向性,這種圖稱為無向圖。
有向圖:
每條邊都有方向性,稱為有向圖。
頂點的度(Degree):
連線頂點的邊的數量稱為頂點的度。頂點的度在有向圖和無向圖中具有不同的意義。
例如上圖無向圖的頂點 1 的度為 3 。
對於有向圖則稍微複雜點,根據頂點的方向性,頂點有入度和出度之分:
入度是以該頂點為端點的入邊數量,記為ID(V)例如:ID(0) = 3。
出度是以該頂點為端點的出邊數量,記為OD(V)例如:OD(1) = 3。
鄰接頂點:
鄰接頂點是指圖結構中一條邊的兩個頂點。無向圖鄰接頂點比較簡單,在有向圖中則意義不同。
有向圖的入邊鄰接頂點:連線該頂點的邊中的起始頂點。例如 <V0,V1>,V1是V0的入邊鄰接頂點。
有向圖的出邊鄰接頂點:連線該頂點的邊中的結束頂點。例如:<V1,V2>,V1是V2的出邊鄰接頂點。
圖的頂點定義:
#include <iostream> using namespace std; #define MaxNum 20 //圖的最大頂點數 #define MaxValue 65535 //最大值 typedef struct { char Vertex[MaxNum]; //儲存頂點資訊 int GType; //圖的型別 int VertexNum; //頂點的數量 int EdgeNum; //邊的數量 int EdgeWeight[MaxNum][MaxNum]; //儲存邊的權 int isTrav[MaxNum]; //遍歷標誌 }GraphMatrix;
圖的建立:
void CreateGraph(GraphMatrix *GM) //建立鄰接矩陣圖 { int i, j, k; int weight; //權 char EstartV, EendV; //邊的起始頂點 cout << "輸入圖中各項頂點資訊" << endl; for (int i = 0; i < GM->VertexNum;i++) //輸入頂點 { getchar(); cout << "第" << i + 1 << "個頂點: " << endl; cin >> GM->Vertex[i]; //儲存到各頂點陣列元素中 } cout << "輸入構成各邊的頂點及權值:\n"; for (k = 0; k < GM->EdgeNum; k++) { getchar(); cout << "第" << k + 1 << "條邊"; cin >> EstartV >> EendV >> weight; for (i = 0; EstartV != GM->Vertex[i]; i++); //在已有頂點中查詢始點 for (j = 0; EendV != GM->Vertex[j]; j++); //在已有頂點中查詢終點 GM->EdgeWeight[i][j] = weight; //對應位置儲存權值 if (GM->GType == 0) //若是無向圖 GM->EdgeWeight[j][i] = weight; //在對角位置儲存權值 } }
清空圖:
void ClearGraph(GraphMatrix *GM)
{
int i, j;
for (i = 0; i < GM->VertexNum; i++) //清空矩陣
{
for (j = 0;j < GM->VertexNum; j++)
{
GM->EdgeWeight[i][j] = MaxValue;
}
}
}
顯示圖:
void OutGraph(GraphMatrix *GM) //輸出鄰接矩陣
{
int i, j;
for (j = 0; j < GM->VertexNum; j++)
{
cout <<"\t"<< GM->Vertex[j]; //在第一行輸出頂點資訊
}
cout << endl;
for (int i = 0; i < GM->VertexNum; i++)
{
cout << GM->Vertex[i];
for (j = 0; j < GM->VertexNum; j++)
{
if (GM->EdgeWeight[i][j] == MaxValue) //若權值為最大值
{
cout << "\t Z"; //用Z表示無窮大
}
else
{
cout <<"\t"<<GM->EdgeWeight[i][j]; //輸出邊的權值
}
}
cout << endl;
}
}
遍歷圖:
1.首先,從陣列中isTrav中選擇一個未被訪問的頂點V,將其標記為1,表示已訪問。
2.接著,從Vi的一個未被訪問過的鄰接頂點出發進行深度優先遍歷。
3.重複 步驟2,直至圖中所有和Vi路徑相通的頂點都被訪問過。
4.重複步驟3,直至所有頂點都被訪問。
void DeepTraOne(GraphMatrix *GM,int n)
{
int i;
GM->isTrav[n] = 1; //標記改頂點已處理過
cout << " " << GM->Vertex[n]; //輸出結點資料
//新增處理節點的操作
for (i = 0; i < GM->VertexNum; i++)
{
if (GM->EdgeWeight[n][i] != MaxValue && !GM->isTrav[n])
{
DeepTraOne(GM, i); //遞迴進行遍歷
}
}
}
//深度優先遍歷
void DeepTraGraph(GraphMatrix *GM)
{
int i;
for (i = 0; i < GM->VertexNum; i++) //清除各頂點遍歷標誌
{
GM->isTrav[i] = 0;
}
cout << "深度優先遍歷節點: ";
for (int i = 0; i < GM->VertexNum; i++)
{
if (!GM->isTrav[i]) //若該頂點未遍歷
{
DeepTraOne(GM, i); //呼叫函式進行遍歷
}
}
cout << endl;
}
main函式:
int main()
{
GraphMatrix GM;
cout << "輸入生成圖的型別: ";
cin >> GM.GType;
cout << "輸入圖的頂點數量: ";
cin >> GM.VertexNum;
cout << "輸入圖的邊的數量: ";
cin >> GM.EdgeNum;
ClearGraph(&GM);
CreateGraph(&GM);
cout << "該圖的鄰接矩陣資料如下: " << endl;
OutGraph(&GM);
DeepTraGraph(&GM);
system("pause");
return 0;
}
測試輸出: