《資料結構與演算法那》第七次 廣度、深度優先遍歷 圖及圖的遍歷(下)
《資料結構與演算法那》第七次課實驗內容
圖及圖的遍歷(下)
實驗目的:
- 熟悉圖的兩種儲存結構:鄰接矩陣和鄰接連結串列。
- 掌握在圖的鄰接表儲存結構上的遍歷演算法的實現。
實驗內容:
- 在已經開發好的c++類adjacencyGraph中,新增兩個成員函式,BFSpanningTree和DFSspanningTree分別輸出該圖的廣度優先生成樹和深度優先生成樹。
- 在已經開發好的c++類linkedGraph中,新增兩個成員函式,BFSpanningTree和DFSpanningTree分別輸出該圖的廣度優先生成樹和深度優先生成樹。
- 兩個儲存方式任選其一完成。
江米條想說的話:
(用的是臨界陣列,這個題連結串列比矩陣更簡單,矩陣都會了,還怕連結串列該幹什麼)
這次的程式碼和上次的程式碼幾乎一樣,就多了兩個函式而已。沒看明白的看我寫的《資料結構與演算法》第六次去。。。。
下面我給大家講一下這兩個演算法:BFS(廣度優先)和DFS(深度優先)
廣度優先BFS (你們記住Breadth就行):
簡單地說:廣度的意思就是一層一層的遍歷。
看圖:
從A點開始訪問順序:A->B->D->E->C->F->G
廣度遍歷是:
1:訪問A
2:訪問B,D,E(B,D,E都是A的鄰接點,按照順序訪問)
3:訪問C(訪問B的鄰接點C,訪問完了C點之後,開始從D,E找)
4:訪問F(因為D的鄰接點沒有,所以從B,D,E中的E點開始找E的下一個,即F)
5:訪問G(訪問F的下一個G)
6:G點之後沒有了,往上找發現F也沒未訪問的子節點了,在往上也發現:E也沒有未訪問的子節點了(B,D,E都沒了),所以再往上看A也沒有未訪問的子節點了,至此,訪問結束。
深度優先DFS (你們記住Depth就行):
簡單地說:深度就是沿著一條路走到底,走完了再折回來走其他的路。
看圖:
從A點開始訪問的順序:A->B->C->D->E->F->G
深度遍歷是:(鄰接連結串列)
1: 訪問A
2: 訪問B(在這個過程裡面,A的鄰接點有B、D、E,但是B的順序在前面,所以先訪問B)
3: 訪問C(在這個過程裡面,B的鄰接點有C、D,但是C的順序在前面,所以先訪問C)
4: 訪問D(C之後沒鄰接點了,所以往上倒一層,找B的另一個鄰接點D)
5: 訪問E(D之後沒鄰接點了,所以往上倒一層,B之後的點都被訪問了,再往上倒一層,找A的另一個鄰接點E)
6: 訪問F(E的下一個是F)
7: 訪問G(F的下一個是G)
8: G訪問沒了,往上倒一層到了F,F的鄰接點都被訪問了,再往上倒一層到了E,E的鄰接點都被訪問了,再再往上倒一層到了A,A的鄰接點也都被訪問了,至此,訪問結束
標頭檔案:
#include<iostream>
using namespace std;
class adjacencyGraph
{
public:
adjacencyGraph(int n, int e);
void setElement(int n, int value);
int getIndex(int value);
void insertEdge(int vertex1, int vertex2);
void eraseEdge(int vertex1, int vertex2);
void BFSpanningTree(int v);
void DFSpanningTree(int v);
void dfs(int v);
void outputGraph();
private:
int **matrix;
int *element;
int numberOfVertices;
int numberOfEdges;
int *reach = new int[numberOfVertices];
int count = 0;
};
adjacencyGraph::adjacencyGraph(int n, int e)
{
numberOfVertices = n;
numberOfEdges = e;
matrix = new int *[numberOfVertices];
for (int i = 0; i < numberOfVertices; i++)
matrix[i] = new int[numberOfVertices];
for (int i = 0; i < numberOfVertices; i++)
for (int j = 0; j < numberOfVertices; j++)
matrix[i][j] = 0;
element = new int[numberOfVertices];
}
void adjacencyGraph::setElement(int n, int value)
{
element[n - 1] = value;
}
int adjacencyGraph::getIndex(int value)
{
for (int i = 0; i < numberOfVertices; i++)
if (element[i] == value)
return i;
}
void adjacencyGraph::insertEdge(int vertex1, int vertex2)
{
matrix[vertex1][vertex2] = 1;
matrix[vertex2][vertex1] = 1;
}
void adjacencyGraph::eraseEdge(int vertex1, int vertex2)
{
matrix[vertex1][vertex2] = 0;
matrix[vertex2][vertex1] = 0;
}
void adjacencyGraph::BFSpanningTree(int v)
{
int l = 0, r = 1;
for (int i = 0; i < numberOfVertices; i++)
reach[i] = NULL;
reach[0] = v;
while (reach[numberOfVertices - 1] == NULL)
{
int tl = l, tr = r;
l = r;
for (tl; tl < tr; tl++)
{
int index = getIndex(reach[tl]);
for (int j = 0; j < numberOfVertices; j++)
if (matrix[index][j] == 1)
{
int k;
for (k = 0; k < r; k++)
if (element[j] == reach[k])
break;
if (k == r)
{
reach[r] = element[j];
r++;
}
}
}
}
cout << "這個無向圖的廣度優先搜尋為:";
for (int i = 0; i < numberOfVertices; i++)
cout << reach[i];
cout << endl;
}
void adjacencyGraph::DFSpanningTree(int v)
{
for (int i = 0; i < numberOfVertices; i++)
reach[i] = NULL;
reach[0] = v;
dfs(v);
for (int i = 0; i < numberOfVertices; i++)
cout << reach[i];
cout << endl;
}
void adjacencyGraph::dfs(int v)
{
int index = getIndex(v);
for (int i = 0; i < numberOfVertices; i++)
//if(reach[i]==0)
if (matrix[index][i] == 1)
{
int k;
for (k = 0; k < count; k++)
if (element[i] == reach[k])
break;
if (k == count)
{
bool t = false;//設定這個變數是為了防止出現從父結點再次遍歷到子節點的情況,比如兩個父結點都連著一個子節點。
for(int a=0;a<count+1;a++)
if (element[i] == reach[a])
{
t = true;
break;
}
if (t == false)
{
count++;
reach[count] = element[i];
dfs(reach[count]);
}
}
}
}
void adjacencyGraph::outputGraph()
{
for (int i = 0; i < numberOfVertices; i++)
{
for (int j = 0; j < numberOfVertices; j++)
cout << matrix[i][j] << " ";
cout << endl;
}
}
主函式:
#include<iostream>
#include"adjacencyGraph.h"
using namespace std;
int main()
{
adjacencyGraph *temp;
temp = new adjacencyGraph(0, 0);
while (1)
{
cout << "1.用鄰接矩陣描述一個無向圖" << endl;
cout << "2.刪除無向圖的一條邊" << endl;
cout << "3.對無向圖廣度優先搜尋"<<endl;
cout<< "4.對無向圖深度優先搜尋"<<endl;
cout << "0.退出" << endl;
int option;
cin >> option;
switch (option)
{
case 1:
{
int n, e;
cout << "請輸入頂點的數目:";
cin >> n;
cout << "請輸入邊的數目:";
cin >> e;
temp = new adjacencyGraph(n, e);
for (int i = 1; i <= n; i++)
{
int value;
cout << "請輸入第" << i << "個頂點";
cin >> value;
temp->setElement(i, value);
}
for (int i = 1; i <= e; i++)
{
int value1, value2;
cout << "請輸入第" << i << "條邊的第1個頂點:";
cin >> value1;
cout << "請輸入第" << i << "條邊的第2個頂點:";
cin >> value2;
temp->insertEdge(temp->getIndex(value1), temp->getIndex(value2));
}
temp->outputGraph();
}
break;
case 2:
{
int value1, value2;
cout << "請輸入要刪除邊的第一個頂點:";
cin >> value1;
cout << "請輸入要刪除邊的第二個頂點:";
cin >> value2;
temp->eraseEdge(temp->getIndex(value1), temp->getIndex(value2));
temp->outputGraph();
}
break;
case 3:
{
int v;
cout<< "請輸入搜尋的起點值:";
cin>>v;
temp->BFSpanningTree(v);
}
break;
case 4:
{
int v;
cout << "請輸入搜尋的起點值:";
cin >> v;
temp->DFSpanningTree(v);
}
break;
case 0:
return 0;
default:
break;
}
}
}