日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

数据结构--图 Graph

發布時間:2024/7/5 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据结构--图 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代碼(基于鄰接表)

  • 廣度優先搜索找到的是最短路徑
/*** @description: BFS* @author: michael ming* @date: 2019/6/4 23:05* @modified by: */ #include <list> #include <queue> #include <iostream> #include <memory.h> using namespace std; class graph {int v;//頂點個數list<int> *adj;//鄰接表 public:graph(int numofvertex){v = numofvertex;adj = new list<int> [v];}~graph(){delete [] adj;}void insertEdge(int s, int t) //無向圖,一次存兩邊{s--;t--;adj[s].push_back(t);adj[t].push_back(s);}void print(){for(int i = 0; i < v; ++i){cout << "鄰接表,節點 " << i << " is \n";for(auto it = adj[i].begin(); it != adj[i].end();++it){cout << *it << " ";}cout << endl;}}void bfs(int s)//從s開始遍歷全部{bool *visited = new bool [v];memset(visited,false, sizeof(bool)*(v));visited[s] = true;//visited存儲已經訪問的節點,避免重復訪問list<int> q;//q.push_back(s);list<int>::iterator it;cout << "從" << s << "開始廣度搜索的結果是:" << endl;while(!q.empty()){int w = q.front();cout << w << " ";q.pop_front();for(it = adj[w].begin(); it != adj[w].end();++it){if(visited[*it]==false){visited[*it] = true;q.push_back(*it);}}}delete [] visited;}void bfs(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存儲已經訪問的節點,避免重復訪問list<int> q;q.push_back(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.front();q.pop_front();for(it = adj[w].begin(); it != adj[w].end();++it){if(visited[*it]==false){prev[*it] = w;//從w找到了it位置,記錄下來if(*it == t){printPath(prev, s, t);//遞歸打印路徑delete [] visited;delete [] prev;return;}visited[*it] = true;q.push_back(*it);}}}delete [] visited;delete [] prev;}void printPath(int *prev, int s, int t){if(prev[t] != -1 && t != s){printPath(prev, s, prev[t]);//遞歸打印路徑}cout << t << " ";} };int main() {graph gp(8);gp.insertEdge(1,2);gp.insertEdge(2,3);gp.insertEdge(1,4);gp.insertEdge(2,5);gp.insertEdge(3,6);gp.insertEdge(4,5);gp.insertEdge(5,6);gp.insertEdge(5,7);gp.insertEdge(6,8);gp.insertEdge(7,8);gp.print();gp.bfs(7);cout << endl;gp.bfs(7,1);return 0; }


最壞情況,起終點很遠,所有點都要進出隊列,每個邊也被訪問一次,時間復雜度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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。