数据结构--图 Graph
生活随笔
收集整理的這篇文章主要介紹了
数据结构--图 Graph
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1. 概念
- 2. 存儲方法
- 2.1 鄰接矩陣 Adjacency Matrix
- 2.2 鄰接表 Adjacency List
- 3. 圖的遍歷
- 3.1 廣度優先搜索BFS(Breadth First Search)
- 3.2 BFS代碼(基于鄰接表)
- 3.3 深度優先搜索DFS(Depth First Search)
- 3.4 DFS代碼(基于鄰接表)
- 3.5 BFS代碼(基于鄰接矩陣)
- 3.6 DFS代碼(基于鄰接矩陣)
1. 概念
頂點的入度,表示有多少條邊指向這個頂點;
頂點的出度,表示有多少條邊是以這個頂點為起點指向其他頂點。
2. 存儲方法
2.1 鄰接矩陣 Adjacency Matrix
存儲比較浪費,有的頂點很多,但是邊很少(微信用戶很多,每個用戶的好友只百個),用鄰接矩陣存儲,其中大部分都是0,浪費。
鄰接矩陣優點。
- 首先,鄰接矩陣的存儲方式簡單、直接,因為基于數組,所以在獲取兩個頂點的關系時,就非常高效。
- 其次,用鄰接矩陣存儲圖的另外一個好處是方便計算(矩陣運算)。
2.2 鄰接表 Adjacency List
鄰接表節省內存,但是查找起來需要遍歷鏈表,可以將鏈表改造成紅黑樹、跳表、散列表、有序動態數組(二分查找)等。
3. 圖的遍歷
3.1 廣度優先搜索BFS(Breadth First Search)
3.2 BFS代碼(基于鄰接表)
- 廣度優先搜索找到的是最短路徑
最壞情況,起終點很遠,所有點都要進出隊列,每個邊也被訪問一次,時間復雜度O(V+E),對于所有頂點都是聯通的,E邊大于等于V-1,可簡寫O(E);
空間復雜度O(V),存儲的空間不會超過頂點個數
3.3 深度優先搜索DFS(Depth First Search)
一條路走到底,發現都訪問過了,還沒找到,返回到上一個岔路口,繼續查找。
3.4 DFS代碼(基于鄰接表)
void dfs_r(int s)//從s開始遞歸法深度搜索遍歷 {cout << "從" << s << "開始深度搜索的結果是(遞歸):" << endl;bool *visited = new bool [v];memset(visited,false, sizeof(bool)*(v));dfs_recu(visited, s);delete [] visited; } void dfs_recu(bool *visited, int s) {list<int>::iterator it;visited[s] = true;cout << s << " ";for(it = adj[s].begin(); it != adj[s].end();++it){if(!visited[*it])dfs_recu(visited, *it);} } void dfs_r(int s, int t)//從s開始遞歸法深度遍歷搜索t {bool found = false;cout << "從" << s << "開始深度搜索" << t << "的結果是(遞歸):" << endl;bool *visited = new bool [v];memset(visited,false, sizeof(bool)*(v));int *prev = new int [v];//記錄搜索的路徑for(int i = 0; i < v; ++i)prev[i] = -1;dfs_recu(visited, prev, found, s, t);printPath(prev, s, t);delete [] visited;delete [] prev; } void dfs_recu(bool *visited, int *prev, bool &found, int s, int t) {if(found == true)//如果已經找到了,for循環剩余的不執行(優化)return;visited[s] = true;if(s == t){found = true;return;}for(auto it = adj[s].begin(); it != adj[s].end();++it){if(!visited[*it]){prev[*it] = s;dfs_recu(visited, prev, found, *it, t);}} } void dfs(int s)//從s開始,非遞歸深度遍歷 {bool *visited = new bool [v];memset(visited,false, sizeof(bool)*(v));visited[s] = true;//visited存儲已經訪問的節點,避免重復訪問stack<int> q;q.push(s);list<int>::iterator it;cout << "從" << s << "開始深度搜索的結果是(非遞歸):" << endl;while(!q.empty()){int w = q.top();q.pop();if(visited[w] == true){cout << w << " ";for(it = adj[w].begin(); it != adj[w].end();++it){if(visited[*it]==false){visited[*it] = true;q.push(*it);}}}}delete [] visited; } void dfs(int s, int t)//從s開始,非遞歸深度遍歷搜索t {if(s == t)return;bool *visited = new bool [v];memset(visited,false, sizeof(bool)*(v));visited[s] = true;//visited存儲已經訪問的節點,避免重復訪問stack<int> q;q.push(s);int *prev = new int [v];//記錄搜索的路徑for(int i = 0; i < v; ++i)prev[i] = -1;list<int>::iterator it;cout << "從" << s << "開始深度搜索" << t << "的結果是(非遞歸):" << endl;while(!q.empty()){int w = q.top();q.pop();if(visited[w] == true){for(it = adj[w].begin(); it != adj[w].end();++it){if(visited[*it]==false){prev[*it] = w;if(*it == t){printPath(prev, s, t);//遞歸打印路徑delete [] visited;delete [] prev;return;}visited[*it] = true;q.push(*it);}}}}delete [] visited;delete [] prev; } gp.dfs_r(6); cout << endl; gp.dfs(6); cout << endl; gp.dfs_r(5,3); cout << endl; gp.dfs(5,3);
深度優先和廣度優先搜索的時間復雜度都是O(E),空間復雜度是 O(V)。
基于鄰接表的 BFS&DFS 完整代碼:https://github.com/hitskyer/course/blob/master/dataAlgorithm/chenmingming/graph/BFS_DFS.cpp
3.5 BFS代碼(基于鄰接矩陣)
/*** @description: 基于鄰接矩陣的無向圖* @author: michael ming* @date: 2019/6/11 21:50* @modified by: */ #include <iostream> #include <queue> #include <stack> using namespace std; #define MaxNum 20 //最大頂點數 #define MaxValue 65535 //最大值(標記矩陣空位) class arrGraph //鄰接矩陣圖 { public:char vertex[MaxNum]; //頂點信息int GType; //圖的類型(0無向圖,1有向圖)int v; //頂點個數int e; //邊數量int ew[MaxNum][MaxNum]; //邊的權重int visited[MaxNum]; //訪問標志arrGraph(int vertexNum, int edgeNum, int gt = 0){v = vertexNum;e = edgeNum;GType = gt;clearGraph();}void creatGraph(){int i, j, k;//循環用計數器int weight;//權重char startV, endV;//邊的起始終止點cout << "輸入圖中各頂點的信息:" << endl;for(i = 0; i < v; ++i){cout << "第" << i+1 << "個頂點:";cin >> vertex[i];}cout << "輸入各邊的起點,終點,權值:" << endl;for(k = 0; k < e; ++k){cout << "第" << k+1 << "條邊:";cin >> startV >> endV >> weight;for(i = 0; startV != vertex[i]; ++i); //查找起點for(j = 0; endV != vertex[j]; ++j); //終點ew[i][j] = weight; //權值,一條邊 i->jif(GType == 0)ew[j][i] = weight; //無向圖,對稱位置一樣的權}}void clearGraph(){int i, j;for(i = 0; i < v; ++i)for(j = 0; j < v; ++j)ew[i][j] = MaxValue; //清空矩陣(每個值置為MaxValue)}void printArrOfGraph(){int i, j;for(j = 0; j < v; ++j)cout << "\t" << vertex[j];//第1行頂點信息cout << endl;for(i = 0; i < v; ++i){cout << vertex[i];for(j = 0; j < v; ++j){if(ew[i][j] == MaxValue)cout << "\t∞";elsecout << "\t" << ew[i][j];}cout << endl;}}int findPos(char ch){int i;for(i = 0; i < v && ch != vertex[i]; ++i);//找到ch的位置ireturn i;}void bfs(char s)//從字符s開始廣度遍歷{int i, k;for(i = 0; i < v; ++i)visited[i] = 0;//訪問標志置0i = findPos(s);if(i >= v)return;visited[i] = 1;queue<char> q;q.push(s);cout << "從 " << s << " 開始廣度優先遍歷結果:" << endl;while(!q.empty()){char w = q.front();cout << w << " ";q.pop();k = findPos(w);for(i = 0; i < v; ++i){if(ew[k][i] != MaxValue && !visited[i]){visited[i] = 1;q.push(vertex[i]);}}}cout << endl;}void bfs(char s, char t)//從字符s開始廣度優先搜索t{if(s == t)return;int i, k;k = findPos(s);if(k >= v)return;//s不存在for(i = 0; i < v; ++i)visited[i] = 0;//訪問標志置0visited[k] = 1;//訪問s,存入隊列queue<char> q;q.push(s);char *prev = new char [v];//記錄搜索的路徑for(i = 0; i < v; ++i)prev[i] = '*';cout << "從 " << s << " 開始廣度優先搜索 " << t << " 路徑:" << endl;while(!q.empty()){char w = q.front();q.pop();k = findPos(w);for(i = 0; i < v; ++i){if(ew[k][i] != MaxValue && !visited[i]){prev[i] = vertex[k]; //從k處找到了i位置,記錄下來if(vertex[i] == t){printPath(prev, s, t, i);//遞歸打印路徑cout << t << endl;delete [] prev;return;}visited[i] = 1;q.push(vertex[i]);}}}delete [] prev;cout << endl;}void printPath(char *prev, char s, char t, int i){int k = findPos(prev[i]);if(prev[k] != '*' && t != s){printPath(prev, s, prev[k], k);//遞歸打印路徑}cout << prev[i] << " ";} };int main() {arrGraph ag(8,10); //8個頂點,10條邊,默認生成無向圖ag.creatGraph(); // A — B — C // | | | // D — E — F // | | // G — H //請輸入A B C D E F G H A B 1 B C 1 A D 1 B E 1 C F 1 D E 1 E F 1 E G 1 F H 1 G H 1cout << "打印圖的鄰接矩陣:" << endl;ag.printArrOfGraph();ag.bfs('B');ag.bfs('A','G'); }3.6 DFS代碼(基于鄰接矩陣)
void dfs_r(char s)//從字符s開始遞歸深度優先遍歷 {int i, j;i = findPos(s);if(i >= v)return;j = i;//j存儲了開始字符s的位置for(i = 0; i < v; ++i)visited[i] = 0;//訪問標志置0cout << "從 " << s << " 開始深度優先遍歷結果(遞歸):" << endl;for(i = 0; i < v; ++i,++j){if(j == v)j = 0;if(!visited[j])//沒有訪問dfs_recu(j);}cout << endl; } void dfs_recu(int k) {visited[k] = 1;cout << vertex[k] << " ";for(int i = 0; i < v; ++i){if(ew[k][i] != MaxValue && !visited[i])dfs_recu(i);} }void dfs_r(char s, char t)//從字符 s 開始遞歸深度優先搜索 t {cout << "從 " << s << " 開始深度優先搜索 " << t << " 路徑(遞歸):" << endl;bool found = false;int i, j;char *prev = new char [v];//記錄搜索的路徑for(i = 0; i < v; ++i)prev[i] = '*';i = findPos(s);j = i;//j存儲了開始字符s的位置if(i >= v)return;if(s == t)return;for(i = 0; i < v; ++i)visited[i] = 0;//訪問標志置0for(i = 0; i < v; ++i,++j){if(j == v)j = 0;if(!visited[j])//沒有訪問dfs_recu(j, prev, found, s, t);}i = findPos(t);printPath(prev, s, t, i);//遞歸打印路徑cout << t << endl;delete [] prev; } void dfs_recu(int k, char *prev, bool &found, char s, char t) {if(found == true)//如果已經找到了,for循環剩余的不執行(優化)return;visited[k] = 1;if(s == t){found = true;return;}for(int i = 0; i < v; ++i){if(ew[k][i] != MaxValue && !visited[i]){prev[i] = vertex[k]; //從k處找到了i位置,記錄下來dfs_recu(i, prev, found, vertex[k], t);}} }void dfs(char s)//從字符s開始深度優先遍歷(非遞歸) {int i, k;i = findPos(s);if(i >= v)return;k = i;//k存儲了開始字符s的位置for(i = 0; i < v; ++i)visited[i] = 0;//訪問標志置0cout << "從 " << s << " 開始深度優先遍歷結果(非遞歸):" << endl;stack<char> q;q.push(s);visited[k] = 1;while(!q.empty()){char w = q.top();q.pop();k = findPos(w);if(visited[k])//訪問過了{cout << w << " ";for(i = 0; i < v; ++i){if(ew[k][i] != MaxValue && !visited[i]){visited[i] = 1;q.push(vertex[i]);}}}}cout << endl; }void dfs(char s, char t)//從字符s開始深度優先搜索t(非遞歸) {cout << "從 " << s << " 開始深度優先搜索 " << t << " 路徑(非遞歸):" << endl;if(s == t)return;int i, k;i = findPos(s);k = i;//k存儲了開始字符s的位置if(i >= v)return;for(i = 0; i < v; ++i)visited[i] = 0;//訪問標志置0char *prev = new char [v];//記錄搜索的路徑for(i = 0; i < v; ++i)prev[i] = '*';stack<char> q;q.push(s);visited[k] = 1;while(!q.empty()){char w = q.top();q.pop();k = findPos(w);if(visited[k])//訪問過了{for(i = 0; i < v; ++i){if(ew[k][i] != MaxValue && !visited[i]){prev[i] = vertex[k]; //從k處找到了i位置,記錄下來if(vertex[i] == t){printPath(prev, s, t, i);//遞歸打印路徑cout << t << endl;delete [] prev;return;}visited[i] = 1;q.push(vertex[i]);}}}}delete [] prev;cout << endl; }測試
ag.dfs_r('E');ag.dfs_r('A','H');ag.dfs('E');//非遞歸版本dfs貌似路徑不太合理,// 如 B E G H F D C A && E G H F C D A B//可能非遞歸版的dfs就不叫dfs了,我瞎說的ag.dfs('A','H');基于鄰接矩陣的 BFS&DFS 完整代碼:https://github.com/hitskyer/course/blob/master/dataAlgorithm/chenmingming/graph/arrayGraph.cpp
總結
以上是生活随笔為你收集整理的数据结构--图 Graph的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 短网址系统
- 下一篇: lisp 中望cad 选项卡_这些高效插