1. 程式人生 > >圖的遍歷(深度優先遍歷)

圖的遍歷(深度優先遍歷)

首先來講一下資料結構中圖的基本概念:

什麼是圖結構:

圖資料結構是每個資料元素之間可以任意關聯,構成了圖結構。正是這種任意關聯性,導致圖結構中的資料關係的複雜性。

典型的圖結構包含兩個部分:

頂點(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;
}

測試輸出: