標籤:沒有 number int 快速 protected ring code 鏈表 訪問
一、圖的儲存
用鄰接表法儲存圖,儲存結構分為兩部分,一部分為儲存圖的所有頂點的數組,另一部分為掛載在數組的每個元素後面的用來表示頂點的鄰接點的鏈表。
1、儲存頂點的結構單元為:
class vnode{public: string nodename; bool visted;//進行圖的遍曆時用於標記圖是否被訪問過 node *next; vnode() { visted = false; next = NULL; }};
鏈表的結構單元為:
class node{public: string nodename; int nodeindex;//節點的索引,用於快速定位節點在頂點數組中的位置 int weight;//權值,用於儲存頂點之間的資訊 node *next; node() { next = NULL; }};
2、現在聲明Graph這個類,類的聲明為(有關圖的遍曆的成員函數也以包含進來):
class Graph{public: Graph(); ~Graph(); bool DeepFirstSearch(int nodeindex); void ClearVisited(); bool WideFirstSearch(int nodeindex);protected: vnode *pvnode; int vnumber;};
3、下面是Graph類的成員函數的定義為(先實現關於圖的儲存的成員函數):
Graph::Graph(){ cout << "請輸入節點的個數:"; cin >> vnumber; pvnode = new vnode[vnumber]; //通過new建立頂點數組 for (int i = 0; i < vnumber; i++) //通過for迴圈將圖的資訊輸入 { cout << endl; cout << "請輸入節點:"; cin >> pvnode[i].nodename; string check; //輸入某個頂點的鄰接點時,以"#"作為輸入的結束標誌 while (1) { cout << "請輸入節點的相鄰節點:"; cin >> check; if (check == "#") { break; }//如果輸入的"#"就跳出輸入迴圈 node *temp = new node; //如果不是,就分配節點記憶體,完善相關資訊 temp->nodename = check; cout << "請輸入相鄰節點的序號和權值:"; cin >> temp->nodeindex >> temp->weight; temp->next = pvnode[i].next; //並將新輸入的節點放到相應的鏈表中 pvnode[i].next = temp; } }}Graph::~Graph() //釋放記憶體時,先釋放鏈表佔用的記憶體,然後釋放數組佔用的記憶體{ node*currentnode = NULL; //釋放鏈表佔用的記憶體 node*temp = NULL; for (int i = 0; i < vnumber; i++) { currentnode = pvnode[i].next; while (currentnode != NULL) { temp = currentnode->next; //儲存當前節點的下一個節點的記憶體 delete currentnode; //釋放當前節點的記憶體 currentnode = temp; //下一個節點作為當前的節點 } } delete[]pvnode; //釋放數組佔用的記憶體}
二、圖的遍曆
1、深度優先遍曆
深度優先遍曆通過遞迴的演算法實現
下面是實現圖的深度優先遍曆的成員函數的實現:
bool Graph::DeepFirstSearch(int nodeindex){ if (nodeindex < 0 || nodeindex >= vnumber) //判斷指定的起始節點是否合法 { cout << "The nodeindex does not exist.."; return false; } if (pvnode[nodeindex].visted == false) //判斷當前節點是否被訪問過,如果沒有,則繼續 { cout << pvnode[nodeindex].nodename << " "; //輸出節點的名字 pvnode[nodeindex].visted = true; //修改訪問記錄 node *currentnode=pvnode[nodeindex].next; //找到當前節點相鄰的一個節點 while (currentnode != NULL) { DeepFirstSearch(currentnode->nodeindex); //通過遞迴繼續上述操作 currentnode = currentnode->next; //換當前節點的另一個相鄰節點試試 } } return true;}
2、廣度優先遍曆
廣度優先遍曆需要藉助隊列這種資料結構。
代碼實現:
bool Graph::WideFirstSearch(int nodeindex){ if (nodeindex < 0 || nodeindex >= vnumber) //判斷輸入的節點索引是否合法 { cout << "The nodeindex does not exist.."; return false; } Queue<int> queue(vnumber); cout << "廣度優先搜尋的遍曆結果為:"; cout << pvnode[nodeindex].nodename << " "; //將起始節點的名字列印出來 pvnode[nodeindex].visted = true; //更改起始節點的訪問記錄 queue.EnQueue(nodeindex); //起始節點入隊列 int temp=0; node *currentnode = NULL; while (queue.QueueEmpty() == false) //對於每一個入隊的節點, { queue.DeQueue(temp); currentnode = pvnode[temp].next; //按入隊順序訪問其相鄰的全部節點 while (currentnode!= NULL) { if (pvnode[currentnode->nodeindex].visted == false) { cout << currentnode->nodename << " "; pvnode[currentnode->nodeindex].visted = true; //已經訪問過的節點更改訪問記錄併入隊 queue.EnQueue(currentnode->nodeindex); } currentnode = currentnode->next; } } cout << endl; return true;}
3、由於這兩種演算法都需要對節點的訪問記錄進行修改,所以每次用這兩種的某一種演算法實現遍曆後需要初始化訪問記錄才能繼續使用。
初始化訪問記錄的函數代碼實現為:
void Graph::ClearVisited(){ for (int i = 0; i < vnumber; i++) { pvnode[i].visted = false; }}
註:完整的代碼在下面賦上,另附上實現隊列的完整代碼
http://files.cnblogs.com/files/Rcchio/Graph.rar
以鄰接表作為儲存結構的圖的深度優先遍曆和廣度優先遍曆(c++版)