圖的儲存結構
1.鄰接矩陣
用一個n×n的二維陣列來儲存,例如node[i][j],代表的是從點i到點j的距離為node[i][j],缺點是無法儲存重邊的情況,比如從i點到j點有兩條路可以走,一條路的長度為3,一條路的長度為5
用一個n×n的二維陣列來儲存,例如node[i][j],代表的是從點i到點j的距離為node[i][j],缺點是無法儲存重邊的情況,比如從i點到j點有兩條路可以走,一條路的長度為3,一條路的長度為5
程式碼實現
int n,m,node;
scanf("%d%d",&n,&m);//n點的個數,m邊的條數
//建立城市之前的關係圖,自身到自身距離為0,兩個城市無法到達則為INF
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
city[i][j]=0;
else city[i][j]=INF;
}
int x,y,r;
//輸入題目給出的兩個城市之間的距離
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&r);
city[x][y]=r;
}
2.向前星
讀入每條邊的資訊,將邊存放在陣列中,把陣列中的邊按照起點順序排序
優點是應對點非常多的情況,可以儲存重邊,但是不能直接判斷任意來兩個頂點之間是否有邊,而且排序要浪費一些時間
程式碼實現
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define INF 99999999
#define MAX 20
using namespace std;
//向前星
int head[MAX];//用來記錄儲存起點為i的第一條邊的位置 ,也就是說在排好序以後,該起點的第一條邊在這個邊的陣列中的位置
//利用head陣列也是為了以後查詢方便,可以查詢從某一頂點出發的所有的邊
struct Node{
int from;//邊的起點
int to;//邊的終點
int w;//邊的權值
};
Node edge[MAX];//建立一個邊的集合的陣列
bool cmp(Node a, Node b)//比較函式
{
if(a.from==b.from && a.to==b.to) return a.w<b.w;//如果兩條邊的起點和終點相同,則按照權值從小到大排序
if(a.from==b.from) return a.to<b.to;//如果兩條邊的起點相同,但是終點不相同,按照重點的大小從小到大排序
return a.from<b.from;//如果兩條邊的起點不相同,則按照起點的大小,從小到大排序
}
int main()
{
int n,m;//n代表點的個數,m代表邊的條數
cin>>n>>m;
for(int i=0;i<m;i++)
cin>>edge[i].from>>edge[i].to>>edge[i].w;
sort(edge,edge+m,cmp); //按上面的排列規則,把邊按順序排好
memset(head,-1,sizeof(head));
head[edge[0].from]=0;//第一條邊的位置為0
for(int i=1;i<m;i++)
if(edge[i].from!=edge[i-1].from) head[edge[i].from]=i;//如果該起點與上一條邊的起點不相同,則是一個新的點
//所以該新的起點的第一條變的的位置就要記錄下來
//遍歷程式碼
for(int i=1;i<=n;i++)
{
for(k=head[i];edge[k].from==i && k<m;k++)//k為頂點為i的第一條邊的位置,如果該條邊的起點不是i,或者該條邊的
{ //位置超出了最大位置,這些邊的位置最大為m-1,因為是從0開始算起的
cout<<edge[k].from<<" "<<edge[k].to<<" "<<edge[k].w<<endl;
}
}
return 0;
}
/*測試資料
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
程式執行效果
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
*/
3.鄰接表
鄰接表就是以每一個節點為起點,分別建立一個單連結串列,用來連結與它直接相鄰的點,通過鄰接表可以訪問與每個節點直接相連的邊與頂點
(1)利用vector動態實現
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define INF 99999999
#define maxn 20
#include<vector>
using namespace std;
struct node{
int to;//終點
int w;//權值
};
vector<node> Map[maxn];
int main()
{
int n,m;
node t;
cin>>n>>m;
for(int i=0;i<m;i++)
{
int from;//form為鄰接表的頭 ,也就是鄰接表的邊的起點
cin>>from>>t.to>>t.w;
Map[from].push_back(t);
}
cout<<endl;
//遍歷每一個點的鄰接表
for(int i=1;i<=n;i++)
{
for(vector<node>::iterator k=Map[i].begin();k!=Map[i].end();k++)//遍歷鄰接表的每一條邊
{
t=*k;
cout<<i<<" "<<t.to<<" "<<t.w<<endl;
}
}
return 0;
}
/*測試資料
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
程式執行效果
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
*/
(2)利用陣列靜態實現(鏈式向前星)
鏈式向前星的建圖效率非常高,讀入結束,建圖就結束,時間複雜度為O(m),空間上使用了兩個陣列,空間複雜度為
O(m+n)
鏈式向前星的優點在於除了必要的邊資訊的儲存空間外,只需要非常少的額外空間即可實現,程式碼和原理都比較簡單,可以儲存重邊,還可以應付點和邊的數量很大的情況,與動態建表相比沒有記憶體管理,更安全,因該說除了不能直接用起點和終點確定是否有邊以外,鏈式向前星幾乎是完美的(以上語句摘自《圖論及應用ACM-ICPC程式設計系列》)
用鄰接表來儲存圖的結構,構圖的時間複雜度為O(m),遍歷每一條邊的時間複雜度也為O(m)
如果一個圖是稀疏圖的話,m要遠小於n,因此稀疏圖用鄰接表來儲存要比鄰接矩陣要好得多
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define INF 0x3f3f3f3f
#define maxn 20
#include<vector>
using namespace std;
struct node{
int to;
int w;
int next;
};
int main()
{
int n,m,from;//form代表鄰接表的第一個點,也就是起點
node Edge[maxn];//node型別的存放邊的陣列
int head[maxn];//用來存放第i個點所對應的第一條邊在Edge陣列裡面的位置
cin>>n>>m;
memset(head,-1,sizeof(head));
//相當於連結串列的前插,就是每次插入一條邊都是插入到該連結串列的第一位置,比如連結串列一開始為1->2->3,後來插入了4,就變成了
//4->1->2->3
for(int i=0;i<m;i++)
{
cin>>from>>Edge[i].to>>Edge[i].w;
Edge[i].next=head[from];
head[from]=i;
}
cout<<endl;
//遍歷每一個點的鄰接表
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=Edge[j].next)//-1代表該鄰接表已經沒有下一條邊了,該點的鄰接表遍歷完成
cout<<i<<" "<<Edge[j].to<<" "<<Edge[j].w<<endl;
}
return 0;
}
/*測試資料
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
程式執行效果
1 3 12
1 2 1
2 4 3
2 3 9
3 5 5
4 6 15
4 5 13
4 3 4
5 6 4
*/
相關文章
- 圖(Graph)——圖的儲存結構
- php圖的儲存結構PHP
- 【資料結構——圖和圖的儲存結構】資料結構
- 【PHP資料結構】圖的概念和儲存結構PHP資料結構
- 圖說HP-lefthand儲存結構
- 儲存結構
- 圖(1)--圖的相關術語與圖的儲存結構
- Redis儲存結構以及儲存格式Redis
- JanusGraph -- 儲存結構
- CentOS 儲存結構CentOS
- MySQL InnoDB的儲存結構總結MySql
- MySQL 5.6 InnoDB儲存引擎體系結構圖MySql儲存引擎
- MySQL的varchar儲存原理:InnoDB記錄儲存結構MySql
- 三種儲存結構
- MySQL Innodb 儲存結構 & 儲存Null值 解析MySqlNull
- 儲存器的層次結構
- 串的順序儲存結構
- 資料結構複雜圖形儲存 PHP 版資料結構PHP
- 圖的儲存結構——鄰接矩陣與鄰接表矩陣
- MySQLInnoDB儲存引擎(一):精談innodb的儲存結構MySql儲存引擎
- InnoDB記錄儲存結構
- HBase 資料儲存結構
- redis 儲存結構原理 2Redis
- oracle物理儲存結構理解Oracle
- Oracle資料儲存結構Oracle
- SAP儲存地點結構
- 二叉樹的儲存結構二叉樹
- 佇列的順序儲存結構佇列
- 佇列的鏈式儲存結構佇列
- 圖解vsan儲存結構/資料恢復方法圖解資料恢復
- 一篇看懂圖資料庫janusgraph儲存結構資料庫
- 庖丁解牛:GIF圖片原理和儲存結構
- 樹的學習——樹的儲存結構
- 圖的儲存
- 儲存結構的種類與比較
- 樹形結構的儲存與查詢
- 從NSM到Parquet:儲存結構的衍化
- Cassandra的內部資料儲存結構