1,邻接矩阵简述
邻接矩阵:采用二维数组的形式来存储图或网。
有向、无向图,有向、无向网都可以采用邻接矩阵的方式存储,下面分别分析一些需要注意的细节点:
1,有向图:有向图的邻接矩阵不根据主对角线对称
2,无向图:根据主对角线对称(因为对称,所以我们只需填充上半三角(或下半三角)即可,但这样也会浪费很多的存储空间,所以此时若我们再利用矩阵压缩的办法来压缩存储为一维数组,那么这一弊端将会被降到最小)
3,有向网:与有向图类似,但是每条边都被赋有权重值
4,无向网:与无向图类似,但是每条边都被赋有权重值(也可压缩存储节约内存)
1.1,邻接矩阵适用情况
从总体上来看,邻接矩阵适合于稠密图
设边数为e,节点数为n,那么
当 e >> 1 / 2 * n * (n - 1)
时,用邻接矩阵比邻接表更节省空间
2,邻接表简述
邻接表的特点就是用表头存储所有的图节点,在存储有向图时,在每个表头结点后都接上以它为弧尾的弧的弧首节点(有的拗口)。这样我们能够很容易的得到一个顶点的出度(即相对应的那个表头结点链表的链表节点个数),而且更好的是我们将邻接表转为逆邻接表是非常方便的,这意味着我们会很容易知道每个节点的入度!
缺点:邻接表的缺陷呢,就是如果你想知道节点i和节点j之间是否直接相连时你需要去到表头节点i和j去分别遍历该条链表。这和邻接矩阵来比显然是麻烦许多的。
所以要合理选择存储结构。
2.1,邻接表适用情况
从总体上来看,邻接表适合于稀疏图
设边数为e,节点数为n,那么
当 e << 1 / 2 * n * (n - 1)
时,用邻接表比邻接矩阵更节省空间
3,邻接矩阵实现代码
看代码,
#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,运行截图
可以看到非常完美的实现了我们需要的功能
4,邻接表实现代码
看代码,
#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,运行截图
同时建成了邻接表和逆邻接表,完美运行!
5,ending
说下我的运行环境:IDE: devc++ ;Standard: c++11;Compiler:MinGW
重心慢慢转向devc++了,这其实是一个很好用的ide,vscode莫名编译缓慢??
老规矩,对你有帮助的话不要吝惜你的赞喔~~peace!