(九)数据结构之邻接矩阵、邻接表存储图

1,邻接矩阵简述

 邻接矩阵:采用二维数组的形式来存储图或网。
有向、无向图,有向、无向网均可以采用邻接矩阵的方式存储,下面分别分析一些须要注意的细节点:
1,有向图:有向图的邻接矩阵根据主对角线对称
2,无向图:根据主对角线对称(由于对称,因此咱们只需填充上半三角(或下半三角)便可,但这样也会浪费不少的存储空间,因此此时若咱们再利用矩阵压缩的办法来压缩存储为一维数组,那么这一弊端将会被降到最小)
3,有向网:与有向图相似,可是每条边都被赋有权重值
4,无向网:与无向图相似,可是每条边都被赋有权重值(也可压缩存储节约内存)
node

1.1,邻接矩阵适用状况

 从整体上来看,邻接矩阵适合于稠密图ios

设边数为e,节点数为n,那么
       当 e >> 1 / 2 * n * (n - 1)
时,用邻接矩阵比邻接表更节省空间c++

2,邻接表简述

 邻接表的特色就是用表头存储全部的图节点,在存储有向图时,在每一个表头结点后都接上以它为弧尾的弧的弧首节点(有的拗口)。这样咱们可以很容易的获得一个顶点的出度(即相对应的那个表头结点链表的链表节点个数),并且更好的是咱们将邻接表转为逆邻接表是很是方便的,这意味着咱们会很容易知道每一个节点的入度!
缺点:邻接表的缺陷呢,就是若是你想知道节点i和节点j之间是否直接相连时你须要去到表头节点i和j去分别遍历该条链表。这和邻接矩阵来比显然是麻烦许多的。
因此要合理选择存储结构。web

2.1,邻接表适用状况

 从整体上来看,邻接表适合于稀疏图数组

设边数为e,节点数为n,那么
       当 e << 1 / 2 * n * (n - 1)
时,用邻接表比邻接矩阵更节省空间ide

3,邻接矩阵实现代码

看代码,svg

#include <iostream>
using namespace std;
//-----------------------------------------图的邻接矩阵存储结构实现--------------------------------// 
#define MAXNUM 20 //最大节点个数

//图的种类类:有向图,有向网,无向图,无向网
typedef enum {
	DG,		//有向图
	DN,		//有向网
	UDG,	//无向图
	UDN		//无向网
} Graph_type;
//图类 
class Graph {
	public:
		Graph(int node, int edge, Graph_type type) : node_num(node), edge_num(edge), kind(type) {
			for (int i = 0; i < node_num; ++i)
				for (int j = 0; j < node_num; ++j)
					matrix[i][j] = 0; //初始化 
		}
		int CreateMatrix();
		void display() const;
		Graph_type kind;
		int edge_num,
			node_num;
		int matrix[MAXNUM][MAXNUM]; //邻接矩阵 
};
//创建邻接矩阵
int Graph::CreateMatrix() {
	cout << "输入两个顶点序号以及一个1表示有边(网须要输入权重值,可为1)" << endl;
	
	int i; int tmpNode1, tmpNode2, weight;
	
	for (i = 0; i < edge_num; ++i) {
		cout << "输入第" << i + 1 << "条边的信息: (" << edge_num - i << "条待输入) ";
		cin >> tmpNode1 >> tmpNode2 >> weight; //不考虑非法输入
		--tmpNode1, --tmpNode2;
		matrix[tmpNode1][tmpNode2] = (kind == DG || kind == UDG) ? 1 : weight;
		matrix[tmpNode2][tmpNode1] = (kind == UDG || kind == UDN) ? weight : 0;
	}
	
	cout << "输入成功" << endl;
}
//输出邻接矩阵 
void Graph::display() const {
	for (int i = 0; i < node_num; ++i) {for (int j = 0; j < node_num; ++j) cout << matrix[i][j] << " ";  cout << endl;}
					
	system("pause");
}
int main() {
	
    cout << "请输入节点数,边数,以及图的种类(0, 1, 2, 3来表示): " << endl;
    int node, edge, type_; Graph_type type;
    
    cin >> node >> edge >> type_; //忽略非法输入
    type_ == 0 ? type = DG : (type_ == 1 ? type = DN : (type_ == 2 ? type = UDG : type = UDN));
	
	Graph G(node, edge, type); //建图
	
	G.CreateMatrix(); //创建邻接矩阵
	
	G.display(); //输出邻接矩阵 
	
    return 0;
}

3.1,运行截图

邻接矩阵运行截图
能够看到很是完美的实现了咱们须要的功能spa

4,邻接表实现代码

看代码,3d

#include <iostream>
using namespace std;
//---------------------------------------图的邻接表存储结构的创建----------------------------------//
#define MAXNUM 20 //最大节点个数 
typedef struct Vertex {
	//elemtype data; 节点的数据域这里我就省略了,只创建邻接表 
	int num; //节点编号
	struct Vertex *next;
	Vertex(int x = 0, struct Vertex *ptr = nullptr) : num(x), next(ptr) {}
} Vertex, *p_Vertex;

typedef struct TableNode { //表头
	Vertex *next;
	TableNode() {next = nullptr;}
} TableNode, TableHead[MAXNUM];

class Graph { //有向图
	public:
		Graph(int node, int edge) : nodeNum(node), edgeNum(edge) {}
		int CreateTable(); //邻接表 
		int CreateTable_reverse(); //逆邻接表 
		void displayTable(int) const; //打印邻接表 
	private:
		TableHead num; //邻接表头
		TableHead numReverse; //逆邻接表头 
		int nodeNum,
			edgeNum;
};
int Graph::CreateTable() {
	cout << "请输入弧尾节点和弧头节点(注意顺序)" << endl; //省略非法输入检查
	
	int node1, node2; p_Vertex ptr; bool mark = false;
	for (int i = 0; i < edgeNum; ++i) {
		cin >> node1 >> node2;
		
		num[node1 - 1].next ? ptr = num[node1 - 1].next, mark = true : (num[node1 - 1].next = new Vertex(node2 - 1), mark = false);
		
		if (mark) {while(ptr->next) ptr = ptr->next; ptr->next = new Vertex(node2 - 1);}
	}
	return 0; //ok
}
void Graph::displayTable(int m) const {
	p_Vertex ptr; 
	
	if (m) cout << "建成的邻接表为: " << endl; else cout << "建成的逆邻接表为: " << endl;
	
	if (m == 1)for (int i = 0; i < nodeNum; ++i) {ptr = num[i].next; cout << i << " -> "; while(ptr) {cout << ptr->num << " -> "; ptr = ptr->next;} cout << "null" << endl;}
	else       for (int i = 0; i < nodeNum; ++i) {ptr = numReverse[i].next; cout << i << " -> "; while(ptr) {cout << ptr->num << " -> "; ptr = ptr->next;} cout << "null" << endl;}
}
int Graph::CreateTable_reverse() {
	//邻接表改逆邻接表
	p_Vertex p1, p2; bool mark = false;
	for (int i = 0; i < edgeNum; ++i) {
		p1 = num[i].next;
	 	while(p1) {
	 		(p2 = numReverse[p1->num].next) ? mark = true : (numReverse[p1->num].next = new Vertex(i), 1);
	 		if (mark) {while(p2->next) p2 = p2->next; mark = false; p2->next = new Vertex(i);}
	 		p1 = p1->next;
		}
	 }
	 return 0; //ok
}
int main()
{
	int node, edge; cout << "请输入图节点数和边的数目" << endl;
	
	cin >> node >> edge;
	
	Graph t(node, edge); t.CreateTable(); t.displayTable(1); cout << endl; //邻接表
	
	t.CreateTable_reverse(); t.displayTable(0); //逆邻接表
	
	return 0;
}

4.1,运行截图

邻接表运行截图
同时建成了邻接表和逆邻接表,完美运行!c++11

5,ending

说下个人运行环境:IDE: devc++ ;Standard: c++11;Compiler:MinGW 重心慢慢转向devc++了,这实际上是一个很好用的ide,vscode莫名编译缓慢?? 老规矩,对你有帮助的话不要吝惜你的赞喔~~peace!