根據分類,圖的搜索分類能夠分爲html
先看BFS和DFS,由於這是最基礎的搜索策略了,BFS是按照深度進行搜索,DFS則是按照廣度進行搜索;數組
其實只要你理解了樹的DFS和BFS,那麼圖的話,只是在其基礎上加了判斷結點是否訪問過,是否聯通而已;.net
先看一幅有向圖指針
能夠發現,其遍歷的順序爲code
0->3->1->2->4htm
其的概念就是一條路走到黑blog
圖的表示方法包括鄰接表,鄰接矩陣等,鄰接矩陣表示的是用一個二維數組表示圖的聯通,其中i行j列表示了i結點和j結點的聯通狀況,若是其爲1,說明是聯通的,若是其爲0,反之;鄰接表表示的是一個一維數組,可是數組中每一個列表包含着是鏈表;遞歸
看個圖加深理解:
隊列
其中a是有向圖/原圖,b是鄰接表表示圖,c是鄰接矩陣表示圖;ip
1. 訪問數組初始化:visited[n] = 0 2. 訪問頂點:visited[v] = 1 3. 取v的第一個鄰接點w; 4. 循環遞歸: while(w存在) if(w未被訪問過) 從頂點w出發遞歸執行; w = v的下一個鄰接點;
1. 棧初始化:visited[n] = 0 2. 訪問頂點:visited[v] = 1 3. 入棧 4. while(棧不爲空) x = 棧的頂元素,而且出棧; if (存在並找到未被訪問的x的鄰接點w) 訪問w:visited[w] = 1 w進棧
上面的尋找下一個鄰接點,須要根據圖是鄰接表仍是鄰接矩陣進行循環判斷;
因爲圖的表示有幾種,因此實現的代碼包括了用鄰接矩陣的圖和鄰接表的圖;
.h文件
typedef struct edge { int vertex; struct edge* next; }Edge; class DFS { public: DFS(); ~DFS(); void Test_M(); void Test_L(); private: // 鄰接矩陣 void createGraph_M(int (*edge)[VERTEXNUM], int start, int end); void displayGraph_M(int (*edge)[VERTEXNUM]); void DFT_M(int (*edge)[VERTEXNUM], int* vertexStatusArr); void DFTCore_M(int (*edge)[VERTEXNUM], int i, int* vertexStatusArr); // 鄰接表 void createGraph_L(Edge** edge, int start, int end); void displayGraph_L(Edge** edge); void delGraph_L(Edge** edge); void DFT_L(Edge** edge, int* vertextStatusArr); void DFTCore_L(Edge** edge, int i, int* vertexStatusArr); }; void DFSTest_M(); void DFSTest_L();
.cpp文件
DFS::DFS() { } DFS::~DFS() { } /*----------------------------鄰接矩陣--------------------------*/ /** * 建立圖 * * @param edge <#edge description#> */ void DFS::createGraph_M(int (*edge)[VERTEXNUM], int start, int end) { edge[start][end] = 1; } /** * 打印存儲的圖 * * @param edge <#edge description#> */ void DFS::displayGraph_M(int (*edge)[VERTEXNUM]) { for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { std::cout << edge[i][j]; } std::cout << std::endl; } } /** * 深度優先遍歷 * * @param edge <#edge description#> */ void DFS::DFT_M(int (*edge)[VERTEXNUM], int* vertexStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { DFTCore_M(edge, i, vertexStatusArr); } std::cout << std::endl; } void DFS::DFTCore_M(int (*edge)[VERTEXNUM], int i, int* vertexStatusArr) { if (vertexStatusArr[i] == 1) return; // 頂點訪問過則再也不訪問 std::cout << i << "->"; vertexStatusArr[i] = 1; // 存在邊的對應關係,才遞歸 for (int j = 0; j < VERTEXNUM; j++) { if (edge[i][j] == 1) { DFTCore_M(edge, j, vertexStatusArr); } } } void DFS::Test_M() { std::cout << "--------------鄰接矩陣表示-----------------" << std::endl; //動態建立存放邊的二維數組 int (*edge)[VERTEXNUM] = (int (*)[VERTEXNUM])malloc(sizeof(int) * VERTEXNUM * VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { edge[i][j] = 0; } } // 存放頂點的遍歷狀態;0:未遍歷,1:已遍歷 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_M(edge); //建立圖 createGraph_M(edge, 0, 3); createGraph_M(edge, 0, 4); createGraph_M(edge, 3, 1); createGraph_M(edge, 3, 2); createGraph_M(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_M(edge); // 遍歷 std::cout << "traversal.." << std::endl; DFT_M(edge, vertexStatusArr); free(edge); } /*----------------------------鄰接表--------------------------*/ void DFS::createGraph_L(Edge** edge, int start, int end) { Edge* nedge = (Edge*)malloc(sizeof(Edge)); nedge->vertex = end; nedge->next = nullptr; edge = edge + start; while (*edge != nullptr) { edge = &((*edge)->next); } *edge = nedge; } void DFS::displayGraph_L(Edge** edge) { Edge* nedge; int edgeCount = 0; for (int i = 0; i < VERTEXNUM; i++) { nedge = *(edge + i); std::cout << i << ":"; while (nedge != nullptr) { std::cout << nedge->vertex << ","; nedge = nedge->next; edgeCount++; } std::cout << std::endl; } std::cout <<"edge count is " << edgeCount << std::endl; } void DFS::delGraph_L(Edge** edge) { Edge *p, *del; for (int i = 0; i < VERTEXNUM; i++) { p = *(edge + i); while (p != nullptr) { del = p; p = p->next; free(del); } edge[i] = nullptr; } free(edge); } void DFS::DFT_L(Edge** edge, int* vertextStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { DFTCore_L(edge, i, vertextStatusArr); } std::cout << std::endl; } void DFS::DFTCore_L(Edge** edge, int i, int* vertexStatusArr) { if (vertexStatusArr[i] == 1) { return; } std::cout << i << "->"; vertexStatusArr[i] = 1; Edge *p = *(edge + i); while (p != nullptr) { DFTCore_L(edge, p->vertex, vertexStatusArr); p = p->next; } } void DFS::Test_L() { std::cout << "--------------鄰接表表示-----------------" << std::endl; // 動態建立存放邊的指針數組 Edge **edge = (Edge**)malloc(sizeof(Edge*)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { edge[i] = nullptr; } // 存放頂點的遍歷狀態:0:未遍歷,1:已遍歷 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_L(edge); //建立圖 createGraph_L(edge, 0, 3); createGraph_L(edge, 0, 4); createGraph_L(edge, 3, 1); createGraph_L(edge, 3, 2); createGraph_L(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_L(edge); // 深度優先遍歷 DFT_L(edge, vertexStatusArr); // 釋放鄰接表佔用的內存 delGraph_L(edge); edge = nullptr; free(vertexStatusArr); vertexStatusArr = nullptr; }
總結:代碼有很強的C的風格,抱歉;這裏面主要看遍歷過程;
先看一幅有向圖
能夠發現,其遍歷的順序爲
0->3->4->1->2
其的概念就是左看看右看看,雨露均沾
1. 初始化隊列:visited[n] = 0 2. 訪問頂點:visited[v] = 1 3. 頂點v加入隊列 4. 循環: while(隊列是否爲空) v = 隊列頭元素 w = v的第一個鄰接點 while(w存在) if(若是w未訪問) visited[w] = 1; 頂點w加入隊列 w = 頂點v的下一個鄰接點
上面的尋找下一個鄰接點,是尋找以前結點的下一個鄰接點,而不是當前的,不然就變成DFS了;
.h文件
typedef struct bedge { int vertex; struct bedge* pre; struct bedge* next; }BEdge; template <class T> class Queue { private: T *arr; int front; int rear; int size; int length; public: Queue(); ~Queue(); void Push(T value); T Pop(); int Size(); int Length(); bool Empty(); bool Full(); }; class BFS { private: BEdge *front; BEdge *rear; public: BFS(); ~BFS(); void Test_M(); void Test_L(); void createGraph_M(int (*edge)[VERTEXNUM], int start, int end); void displayGraph_M(int (*edge)[VERTEXNUM]); void BFT_M(int (*edge)[VERTEXNUM], int *vertexStatusArr); void BFTCore_M(int (*edge)[VERTEXNUM], int i, int *vertexStatusArr); void createGraph_L(BEdge** edge, int start, int end); void displayGraph_L(BEdge** edge); void delGraph_L(BEdge** edge); void BFT_L(BEdge** edge, int* vertextStatusArr); void BFTCore_L(BEdge** edge, int i, int* vertexStatusArr); }; void BFSTest_M(); void BFSTest_L();
.cpp文件
template <class T> Queue<T>::Queue() { size = 10; arr = new T[size]; front = rear = length = 0; } template <class T> Queue<T>::~Queue() { delete [] arr; } template <class T> void Queue<T>::Push(T value) { // 大於原數組長度,建立新數組,賦值給新數組 if (length == size) { int nsize = size * 2; int * narr = new T(nsize); int i = 0; for (; i < length; i++) { narr[(front + i) % nsize] = arr[(front + i) % size]; } rear = (front + i) % nsize; arr = narr; size = nsize; } arr[rear] = value; rear = (rear + 1) % size; ++length; } template <class T> T Queue<T>::Pop() { T temp = arr[front]; front = (front + 1) % size; // 原來的內存塊沒有作到真正的刪除 --length; return temp; } template <class T> int Queue<T>::Size() { return size; } template <class T> int Queue<T>::Length() { return length; } template <class T> bool Queue<T>::Empty() { return length == 0; } template <class T> bool Queue<T>::Full() { return length == size; } BFS::BFS() { } BFS::~BFS() { } void BFS::createGraph_M(int (*edge)[VERTEXNUM], int start, int end) { edge[start][end] = 1; } void BFS::displayGraph_M(int (*edge)[VERTEXNUM]) { for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { std::cout << edge[i][j]; } std::cout << std::endl; } } void BFS::BFT_M(int (*edge)[VERTEXNUM], int *vertexStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { BFTCore_M(edge, i, vertexStatusArr); } std::cout << std::endl; } void BFS::BFTCore_M(int (*edge)[VERTEXNUM], int i, int *vertexStatusArr) { Queue<int> queue; queue.Push(i); while (!queue.Empty()) { int t = queue.Pop(); if (vertexStatusArr[t] == 0) { std::cout << t << "->"; vertexStatusArr[t] = 1; for (int i = 0; i < VERTEXNUM; i++) { if (edge[t][i] == 1) { queue.Push(i); } } } } } void BFS::Test_M() { std::cout << "--------------鄰接矩陣表示-----------------" << std::endl; //動態建立存放邊的二維數組 int (*edge)[VERTEXNUM] = (int (*)[VERTEXNUM])malloc(sizeof(int) * VERTEXNUM * VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { edge[i][j] = 0; } } // 存放頂點的遍歷狀態;0:未遍歷,1:已遍歷 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_M(edge); //建立圖 createGraph_M(edge, 0, 3); createGraph_M(edge, 0, 4); createGraph_M(edge, 3, 1); createGraph_M(edge, 3, 2); createGraph_M(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_M(edge); // 遍歷 std::cout << "traversal.." << std::endl; BFT_M(edge, vertexStatusArr); free(edge); } void BFS::createGraph_L(BEdge** edge, int start, int end) { BEdge* nedge = (BEdge*)malloc(sizeof(BEdge)); nedge->vertex = end; nedge->next = nullptr; edge = edge + start; while (*edge != nullptr) { edge = &((*edge)->next); } *edge = nedge; } void BFS::displayGraph_L(BEdge** edge) { BEdge* nedge; int edgeCount = 0; for (int i = 0; i < VERTEXNUM; i++) { nedge = *(edge + i); std::cout << i << ":"; while (nedge != nullptr) { std::cout << nedge->vertex << ","; nedge = nedge->next; edgeCount++; } std::cout << std::endl; } std::cout <<"edge count is " << edgeCount << std::endl; } void BFS::delGraph_L(BEdge** edge) { BEdge *p, *del; for (int i = 0; i < VERTEXNUM; i++) { p = *(edge + i); while (p != nullptr) { del = p; p = p->next; free(del); } edge[i] = nullptr; } free(edge); } void BFS::BFT_L(BEdge** edge, int* vertextStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { BFTCore_L(edge, i, vertextStatusArr); } std::cout << std::endl; } void BFS::BFTCore_L(BEdge** edge, int i, int* vertexStatusArr) { Queue<int> queue; queue.Push(i); while (!queue.Empty()) { int t = queue.Pop(); if (vertexStatusArr[t] == 0) { std::cout << t << "->"; vertexStatusArr[t] = 1; BEdge* p = *(edge + t); while (p != nullptr) { queue.Push(p->vertex); p = p->next; } } } } void BFS::Test_L() { std::cout << "--------------鄰接表表示-----------------" << std::endl; // 動態建立存放邊的指針數組 BEdge **edge = (BEdge**)malloc(sizeof(BEdge*)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { edge[i] = nullptr; } // 存放頂點的遍歷狀態:0:未遍歷,1:已遍歷 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_L(edge); //建立圖 createGraph_L(edge, 0, 3); createGraph_L(edge, 0, 4); createGraph_L(edge, 3, 1); createGraph_L(edge, 3, 2); createGraph_L(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_L(edge); // 深度優先遍歷 BFT_L(edge, vertexStatusArr); // 釋放鄰接表佔用的內存 delGraph_L(edge); edge = nullptr; free(vertexStatusArr); vertexStatusArr = nullptr; }
參考: