邻接矩阵
Posted lgaaip
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了邻接矩阵相关的知识,希望对你有一定的参考价值。
(以下图为例子)采用邻接矩阵的方法定义图的数据结构,并实现图的深度优先周游算法。
1.首先先定义并实现图的边Edge类,Edge类中的成员变量有:from->起点 to->终点 weight->权值(权值初始化为0)
Edge.h
1 class Edge
2 {
3 public:
4 int from, to, weight;
5 public:
6 Edge() {
7 from = -1;
8 to = -1;
9 weight = 0;
10 }
11
12 Edge(int f, int t, int w){
13 from = f;
14 to = t;
15 weight = w;
16 }
17 ~Edge() {}
18 };
2.定义图的基类,便于邻接矩阵的继承
Graph.h
1 #include "Edge.h"
2 class Graph
3 {
4 protected:
5 const int UNVISITED;
6 const int VISITED;
7 public:
8 int numVertex; //图中顶点的总个数
9 int numEdge; //边数
10 int *Mark; //标记
11 //int *Indegree; //存放图中顶点的入度
12 public:
13 bool IsEdge(Edge oneEdge); //判断是否为边
14 Graph(int numVertex);
15 ~Graph();
16 };
Graph.cpp
1 #include "Graph.h"
2
3 Graph::Graph(int numVertex):UNVISITED(0),VISITED(1){
4 this->numVertex = numVertex;
5 this->numEdge = 0; //初始化顶点数为0
6 this->Mark = new int [numVertex]; //为标记数组动态分配空间
7 //this->Indegree = new int [numVertex];
8
9 for (int i = 0; i < numVertex; i++)
10 {
11 Mark[i] = UNVISITED; //将全部点初始化为未访问
12 //Indegree[i] = 0;
13 }
14 }
15
16 Graph::~Graph(){
17 delete []Mark;
18 //delete []Indegree;
19 }
20
21 bool Graph::IsEdge(Edge oneEdge){
22 if (oneEdge.weight > 0 && oneEdge.to >= 0)
23 {
24 return true;
25 }
26 else return false;
27 }
3.定义Graph类的子类,将图转换为邻接矩阵
tips: Initialize函数形参中的*pWArray2D传进的是一个二维数组。
Graphm.h
1 #include "Graph.cpp"
2
3 class Graphm:public Graph
4 {
5 private:
6 int **matrix; //指向邻接矩阵的指针
7 public:
8 Edge FirstEdge(int oneVertex); //返回以oneVertex为顶点的第一条Edge
9 Edge NextEdge(Edge preEdge); //返回与preEdge有相同顶点的下一条边
10 void setEdge(int from,int to,int weigth); //设置边
11 void delEdge(int from,int to); //删除边
12 void Initialize(Graphm *Graphm,int *pWArray2D ); //初始化图
13 void Visited(Graphm &M,int v); //输出访问过的点
14 void DFS(Graphm &M,int v); //深度优先周游
15 int ToVertex(Edge oneEdge); //返回边的终点
16 void Travel(Graphm &G,int startVertex); //周游全图
17 Graphm(int numVertex);
18 ~Graphm();
19 };
Graphm.cpp
1 #include "Graphm.h"
2 #include <iostream>
3 using namespace std;
4
5 //构造函数
6 Graphm::Graphm(int numVertex):Graph(numVertex){
7 int i,j;
8 matrix = (int **)new int *[numVertex]; //申请matrix数组行向量数组
9
10 for (i = 0; i < numVertex; i++){
11 matrix[i] = new int[numVertex]; //申请行的存储空间(列向量)
12 }
13
14 for (i = 0; i < numVertex; i++){
15 for (j = 0; j < numVertex; j++){
16 matrix[i][j] = 0;
17 }
18 }
19 cout << "构造函数执行!" << endl;
20 }
21 //析构函数释放二维数组的动态分配的空间
22 Graphm::~Graphm(){
23 for (int i = 0; i < numVertex; i++)
24 {
25 delete [] matrix[i];
26 }
27 delete [] matrix;
28 cout << "释放空间成功!" << endl;
29 }
30 //初始化图
31 void Graphm::Initialize(Graphm *Graphm,int *pWArray2D){
32 cout << "开始初始化!" << endl;
33 int N = numVertex;
34 int array_i_j = 0;
35 for (int i = 0; i < N; i++)
36 {
37 for (int j = 0; j < N; j++)
38 {
39 array_i_j = *(pWArray2D + i*N + j); //获得二维数组中每一个元素的值
40 //cout << array_i_j << endl;
41 if (array_i_j > 0) //当元素的值大于0时,证明有从i指向j的边
42 {
43 Graphm->setEdge(i,j,array_i_j); //设置边
44 }
45 }
46 }
47 cout << "初始化成功!" << endl;
48 /*for (int i = 0; i < numVertex; i++)
49 {
50 for (int j = 0; j < numVertex; j++)
51 {
52 cout << matrix[i][j] << " ";
53 }
54 cout << endl;
55
56 }*/
57 }
58 //返回以oneVertex为顶点的第一条Edge
59 Edge Graphm::FirstEdge(int oneVertex){
60 Edge myEdge;
61 myEdge.from = oneVertex;
62
63 for (int i = 0; i < numVertex; i++)
64 {
65 if (matrix[oneVertex][i] != 0)
66 {
67 myEdge.to = i;
68 myEdge.weight = matrix[oneVertex][i];
69 break;
70 }
71 }
72 return myEdge;
73 }
74 //返回与preEdge有相同顶点的下一条Edge
75 Edge Graphm::NextEdge(Edge preEdge){
76 Edge myEdge;
77 myEdge.from = preEdge.from;
78 if (preEdge.to+1 < numVertex)
79 {
80 for (int i = preEdge.to+1; i < numVertex; i++)
81 {
82 if (matrix[preEdge.from][i] != 0)
83 {
84 myEdge.to = i;
85 myEdge.weight = matrix[preEdge.from][i];
86 break;
87 }
88 }
89 }
90 return myEdge;
91 }
92 //为图设置边
93 void Graphm::setEdge(int from,int to,int weigth){
94 if (matrix[from][to] <= 0)
95 {
96 numEdge++; //边的个数加1
97 //Indegree[to]++;
98 }
99 matrix[from][to] = weigth;
100 }
101 //删除边
102 void Graphm::delEdge(int from,int to){
103 if (matrix[from][to] > 0)
104 {
105 numEdge--; //边的个数减1
106 //Indegree[to]--;
107 }
108 matrix[from][to] = 0;
109 }
110 //输出访问过的点
111 void Graphm::Visited(Graphm &M,int v){
112 cout << "v" << v << " ";
113 }
114 //返回边的终点
115 int Graphm::ToVertex(Edge oneEdge){
116 return oneEdge.to;
117 }
118 //深度优先周游
119 void Graphm::DFS(Graphm &M,int v){
120 M.Mark[v] = VISITED;
121 Visited(M,v);
122 for (Edge e = M.FirstEdge(v); M.IsEdge(e); e = M.NextEdge(e))
123 {
124 if (M.Mark[M.ToVertex(e)] == UNVISITED)
125 {
126 //cout << M.ToVertex(e) << endl;
127 DFS(M,M.ToVertex(e));
128 }
129 }
130 }
131 //周游完整的图
132 void Graphm::Travel(Graphm &G,int startVertex){
133 DFS(G,startVertex); //不一定能周游每一个顶点
134 //更换顶点周游
135 for (int i = 0; i < numVertex; i++)
136 {
137 if (G.Mark[i] == UNVISITED)
138 {
139 DFS(G,i);
140 }
141 }
142 }
4.主函数的实现
tips: 先根据图画出邻接矩阵,再将邻接矩阵作为实参进行传递
Main.cpp
1 #include "Graphm.cpp"
2 #define N 8
3 int main(int argc, char const *argv[])
4 {
5
6 //int N = 8;
7 int M[N][N] = {
8 0,0,0,1,0,0,0,0,
9 1,0,0,0,0,0,0,0,
10 1,1,0,0,0,0,0,1,
11 0,1,0,0,0,1,0,0,
12 0,0,1,0,0,0,0,0,
13 0,0,0,0,0,0,0,0,
14 0,0,0,0,1,1,0,0,
15 0,1,0,0,1,1,1,0
16 };
17 Graphm G(N);
18 G.Initialize(&G,(int*)M);
19 cout << "全部深度周游:";
20
21 G.Travel(G,3);
22 cout << endl;
23
24 return 0;
25 }
注:以下总结仅代表个人观点(如有错误,欢迎指出)
总结:1.将图写为基类在此处体现出来的意义其实并不大(在此题中完全可以将Graph类与Graphm类合并起来),但是也是为了养成良好的习惯。
2.主函数中二维数组的传递值得一记,传递的过程将其当成一位数组进行传递。
3.周游的过程中需要考虑到当图为不连通图时,以某个顶点为起点时可能周游出来的结果不完整(以上的Travvel函数则能周游出全部的点。
4.熟练掌握根据图画出对应的邻接矩阵。
5.无权图的权值可设为1。
6.动态分配的空间记得手动释放,最好的做法是写在析构函数中。
以上是关于邻接矩阵的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode207.课程表 | BFS DFS 邻接表 邻接矩阵
LeetCode207.课程表 | BFS DFS 邻接表 邻接矩阵
LeetCode207.课程表 | BFS DFS 邻接表 邻接矩阵