图的三种表示方法 邻接矩阵,邻接表,邻接表改进版 及其优劣分析(附代码)

图有三种表示方法:
**1.邻接矩阵:**利用一个n*n大小的方阵,
A[i][j] = 1表示顶点 ij 是相邻的,即 ij 之间有一条边
A[i][j] = 0表示顶点 ij 是不相邻的,即 ij 之间有没有边

#include<iostream>
#define max 10
using namespace std;

int V;//顶点个数
int E;//边的个数
int adjm[max][max] = {0};

void initE(int x,int y, int w);//初始化边,w为坐标

int main(){ 
 	for(int i = 0; i < 10; i++){//输出邻接矩阵 
 	 	for(int j = 0; j < 10; j++){
    			cout << adjm[i][j] << " ";
  		}
  		cout << endl;
 	}
 	return 0;
}
void initE(int x,int y, int w){ //w为坐标 
 	adjm[x][y] = w;
}

邻接矩阵的实现代码比较简单,下面分析一下其时间和空间的复杂度。

空间复杂度:
O(V^2) 即节点个数的平方,如果有3000个节点,那么需要开出的空间为9x10^6,需要改进

时间复杂度:
建图: O(E) 有E条边,那么E条边的信息都需要存储,这个时间复杂度无法继续提升
查询两点是否相邻: O(1) 即判断a[i][j]是否为1即可,这个时间复杂度也无法提升
**查询某一顶点的邻居:**O(V) 判断a[i]这个数组中有多少个元素为1

其空间复杂度能否修改为O(V+E)呢,即V个节点和E条边的信息存储空间大小为O(V+E)

邻接表解决了这个问题:
在这里插入图片描述

邻接表的大致思想如上图所示,这里不再用文字叙述
代码实现(无向有权图):

typedef struct AdjNode{
 	int N;//Adjvex是该邻接点自己在顶点表中的位
 	//置(顶点表中的数组索引值),而不是与其相连的顶点在顶点表中的位置,更不是该节点保存的数据。
 	int w;//权重
 	AdjNode* next; 
}AdjN;

typedef struct VNode{
 	int data;
 	AdjN* first;
}VN;

typedef struct Graph{
 	int v;//顶点个数
 	int e;//边的个数 
 	VN ag[max];
}G;

void initG(G* g);
void printG(G* g);//打印节点信息 
void printLink(G* g);//打印链表信息 
bool hasedge();//暂未实现  快速查重 
int  nei_v();//暂未实现 

int main(){
 G* g = (G*)malloc(sizeof(G));
 initG(g);
 printG(g);
 printLink(g);
 
 return 0;
}

void initG(G* g){
 	cout<<"输入顶点和边的个数:";
 	int v,e; 
	cin >> v >> e;
 	g->v = v;
 	g->e = e;
 	cout<<"请输入个顶点数据:" ;
 	int data;
 	for(int i = 0; i < g->v; i++){
  		cin >> data;
  		g->ag[i].data = data;
  		g->ag[i].first = NULL; 
 	}
  	for(int i = 0; i < g->e; i++){
  		int p1, p2, w;
  		cout<<"输入边:"; 
  		cin >> p1 >> p2 >> w;
  		AdjN* node1 = (AdjN*)malloc(sizeof(AdjN)); 
  		node1->N = p2;
  		node1->w = w;
  		AdjN* temp = g->ag[p1].first;
  		g->ag[p1].first = node1;
  		node1->next = temp; 
    		//双向 
  		AdjN* node2 = (AdjN*)malloc(sizeof(AdjN)); 
  		node2->N = p1;
  		node2->w = w;
  		temp = g->ag[p2].first;
  		g->ag[p2].first = node2;
  		node2->next = temp; 
 	}
}

void printG(G* g){//打印节点信息 
 	for(int j = 0; j < g->v; j++){
  		cout << j << " " << g->ag[j].data <<endl;
 	}
}

void printLink(G* g){//打印链表信息 
 	for(int i = 0; i < g->v; i++){
  		cout << i <<" ";
  		AdjN * Node = g->ag[i].first;
  		while(Node != NULL){
   		cout<< Node->N << "(" << Node->w << ") ";
   		Node = Node->next;
  	}
  	cout << endl;
 	} 
} 

在这里插入图片描述

空间复杂度分析:O(V+E)已经达到最优

时间复杂度:主要分析其查重能力,即查看一个顶点与另外一个顶点是否存在一条边时:O(degree(V)),取决于该顶点的度。
邻接表的问题
在快速查重的问题(任给两个节点,判断这两个节点之间是否有边)上的时间复杂度为O(degree(V))
而在V比较大时,其表现性能并不是那么完美
解决方法
针对其主要问题,
若使用链表,其查询的时间复杂度必然为线性的
若使用哈希表,其查询时间复杂度为O(1)
若使用红黑树,其查询时间复杂度为O(logV)
采用不同的数据结构,可降低其查询时间复杂度

下面为邻接表的升级版代码:

typedef struct VNode{
 int data;
 map<int,int> mp;//map key 是节点号,即该节点到key之间有一条边,权重是value 
}VN;

typedef struct Graph{
 int v,e;
 VN ag[max];
}G;

void initG(G* g);
void printG(G* g);//打印节点信息 
void printLink(G* g);//打印链表信息 

int main(){
 G* g = new G;
 initG(g);
 printG(g);
 printLink(g);
 
 return 0;
} 

void initG(G* g){
 cout<< "Input the amount of Node and Edge: ";
 cin >> g->v >> g->e ;
 
 //Input the data of Node
 cout<< "Input Data:" << endl;
 for(int i = 0; i < g->v; i++){
  cin >> g->ag[i].data ; 
 }
 
 //Input the edge and weight
 cout<< "Input Edge and Weight:"<<endl;
 for(int i = 0; i < g->e; i++){
  int node1, node2, w;
  cin >> node1 >> node2 >> w;
  g->ag[node1].mp[node2] = w; 
  g->ag[node2].mp[node1] = w; //无向图
 }
}

void printG(G* g){//打印节点信息
 cout<<"Output The Info of Node:"<<endl;
 
 for(int i = 0; i < g->v; i++){
  cout<< i <<" "<< g->ag[i].data << endl;
 } 
}

void printLink(G* g){//打印链表信息
 cout << "OutPut The Info of NLink:"<<endl;
 
 for(int i = 0; i < g->v; i++){
  cout << i << " ";
  for(map<int,int>::iterator it = g->ag[i].mp.begin(); it != g->ag[i].mp.end(); it++){
   cout << it->first << "(" << it->second << ")" << " ";
  }
  cout << endl;
 }
} 

在这里插入图片描述在输出中可发现,每个顶点都是按顺序输出的,虽然我用的时hash_map,但是在STL中其map是用红黑树实现的,其在内部会自动排序,为以后的算法提高了效率。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
邻接矩阵邻接是两种常用的表示方法。下面是Java代码实现邻接矩阵邻接的示例: 1. 邻接矩阵表示的Java代码实现: ```java import java.util.Arrays; class Graph { private int[][] adjMatrix; private int numVertices; public Graph(int numVertices) { this.numVertices = numVertices; this.adjMatrix = new int[numVertices][numVertices]; } public void addEdge(int src, int dest) { // 无向,所以需要在两个位置都设置为1 adjMatrix[src][dest] = 1; adjMatrix[dest][src] = 1; } public void printGraph() { for (int i = 0; i < numVertices; i++) { System.out.print("Vertex " + i + " is connected to: "); for (int j = 0; j < numVertices; j++) { if (adjMatrix[i][j] == 1) { System.out.print(j + " "); } } System.out.println(); } } } public class Main { public static void main(String[] args) { Graph graph = new Graph(5); graph.addEdge(0, 1); graph.addEdge(0, 4); graph.addEdge(1, 2); graph.addEdge(1, 3); graph.addEdge(1, 4); graph.addEdge(2, 3); graph.addEdge(3, 4); graph.printGraph(); } } ``` 2. 邻接表示的Java代码实现: ```java import java.util.LinkedList; class Graph { private int numVertices; private LinkedList<Integer>[] adjList; public Graph(int numVertices) { this.numVertices = numVertices; this.adjList = new LinkedList[numVertices]; for (int i = 0; i < numVertices; i++) { adjList[i] = new LinkedList<>(); } } public void addEdge(int src, int dest) { adjList[src].add(dest); adjList[dest].add(src); } public void printGraph() { for (int i = 0; i < numVertices; i++) { System.out.print("Vertex " + i + " is connected to: "); for (int j : adjList[i]) { System.out.print(j + " "); } System.out.println(); } } } public class Main { public static void main(String[] args) { Graph graph = new Graph(5); graph.addEdge(0, 1); graph.addEdge(0, 4); graph.addEdge(1, 2); graph.addEdge(1, 3); graph.addEdge(1, 4); graph.addEdge(2, 3); graph.addEdge(3, 4); graph.printGraph(); } } ``` 以上代码示例分别实现了邻接矩阵邻接表示的Java代码。你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值