一、图
一、临接表
表示方法如下:
带权值的无向图的构建:
#define MaxInt 32767 // 极大值
#define MVNum 100 // 最大定点数
typedef int ArcType; // 边的权值类型
typedef char VerTexType; // 顶点数据类型//弧(边)的结点结构
struct ArcNode
{int adjvex; // 该边指向顶点的下标struct ArcNode *nextarc; // 下一条边指针ArcType info; // 边的权值
};// 顶点的结点结构
typedef struct VNode
{VerTexType data; // 顶点信息struct ArcNode *firstarc; // 指向第一条边关联该点的边
} VNode, AdjList[MVNum];// 图的结构定义
typedef struct
{AdjList vertices;int vexnum, arcnum; // 图的顶点数和边数
} ALGraph;
创建图:
// 采用邻接表表示法创建无向网
Status CreateUDG(ALGraph &G)
{cin >> G.vexnum >> G.arcnum; // 输入总顶点数与总边数for (int i = 0; i < G.vexnum; ++i){cin >> G.vertices[i].data;G.vertices[i].firstarc = NULL;}for (int k = 0; k < G.arcnum; ++k){char v1, v2;cin >> v1 >> v2;int i = LocateVex(G, v1);int j = LocateVex(G, v2);ArcNode *p1 = new ArcNode;p1->adjvex = j;p1->nextarc = G.vertices[i].firstarc;G.vertices[i].firstarc = p1;ArcNode *p2 = new ArcNode;p2->adjvex = i;p2->nextarc = G.vertices[j].firstarc;G.vertices[j].firstarc = p2;}return 0;
}//顶点在顶点表中的下标
int LocateVex(ALGraph G, VerTexType u)
{int i;for (int i = 0; i < G.vexnum; ++i)if (u == G.vertices[i].data) return i;return -1;
}
二、临接矩阵
表示如下:
带权值的有向图的构建:
#include <bits/stdc++.h>
using namespace std;
#define MaxVertices 100 //假设包含的最大结点数
#define MaxWeight -1 //假设两点不邻接的正无穷值//定义结点
struct AdjMarix {int Vertices[MaxVertices]; //存储结点信息int Edge[MaxVertices][MaxVertices] = { 0 }; //存储每条边的权值int numV; //当前顶点的个数int numE; //当前边的个数
};void CreatGraph(AdjMarix *G) {int vi, vj, w;cout << "请输入顶点数量:" << endl;cin >> G->numV;cout << "请输入顶点信息:" << endl;//输入结点的编号并初始化for (int i = 0; i < G->numV; i++) {cin >> vi;G->Vertices[i] = vi;G->Edge[i][i] = MaxWeight; //初始化过程先默认权值为无穷大}cout << "请输入边的数量:" << endl;cin >> G->numE;cout << "请输入边的信息:" << endl;for (int i = 0; i < G->numE; i++) {cin >> vi >> vj >> w; //vi、vj为邻接矩阵对应点的坐标,w为边的权值G->Edge[vi - 1][vj - 1] = w;//G->Edge[vj-1][vi-1]=w; 无向图需要再加上这一句}
}//遍历图,展示邻接表矩阵
void ShowGraph(AdjMarix *G) {for (int i = 0; i < G->numV; i++) {for (int j = 0; j < G->numV; j++) {cout << G->Edge[i][j] << " ";}cout << endl;}
}int main() {AdjMarix AM;CreatGraph(&AM);ShowGraph(&AM);
}
输入输出的结果为:
三、图的宽度优先遍历
1,利用队列实现
2,从源节点开始依次按照宽度进队列,然后弹出
3,每弹出一个点,把该节点所有没有进过队列的邻接点放入队列
4,直到队列变空
邻接矩阵版:
#include <iostream>
#include <queue>using namespace std;#define MaxVertexNum 100 //顶点数目的最大值// VertexType,顶点的数据类型
template<typename VertexType>
class MGraph {
private:VertexType Vex[MaxVertexNum]; //顶点表int Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵,边表int vexnum, arcnum; //图的当前顶点数和弧数bool inq[MaxVertexNum]; //如果顶点i已入过,inq[i]==true。初值为falsevoid BFS(int u) { //遍历u所在的连通块queue<int> q; //定义队列qq.push(u); //初始顶点u入队inq[u] = true; //设置u已入过队while (!q.empty()) { //只要队列非空u = q.front(); //取出队首元素并访问cout << Vex[u] << "\t";q.pop(); //队首元素出队for (int v = 0; v < vexnum; v++)//如果u的邻接点v未曾加入过队列if (Edge[u][v] == 1 && inq[v] == false) {//将v入队并标记已入队q.push(v);inq[v] = true;}}}public:MGraph() {for (int i = 0; i < MaxVertexNum; i++) {inq[i] = false;for (int k = 0; k < MaxVertexNum; k++)Edge[i][k] = 0;}}void create() {int row, col;cin >> vexnum >> arcnum; //输入实际图的顶点数和边数for (int i = 0; i < vexnum; i++) //输入顶点信息cin >> Vex[i];for (int i = 0; i < arcnum; i++) { //输入边信息cin >> row >> col;Edge[row][col] = 1;}}void BFSTrave() { //遍历图Gfor (int u = 0; u < vexnum; u++) //枚举所有顶点if (inq[u] == false)BFS(u); //遍历u所在的连通块}
};int main() {MGraph<string> G;G.create();G.BFSTrave();return 0;
}
邻接表版:
#include <iostream>
#include <queue>using namespace std;#define MaxVertexNum 100 //顶点数目的最大值struct ArcNode { //边表结点int adjvex; //该弧所指向的顶点的位置ArcNode *next; //指向下一条弧的指针
};template<typename VertexType>
struct VNode { //顶点表结点VertexType data; //顶点信息ArcNode *first; //指向第一条依附该顶点的弧的指针
};template<typename VertexType>
class ALGraph { //ALGraph是以邻接表存储的图类型
private:VNode<VertexType> vertices[MaxVertexNum]; //邻接表int vexnum, arcnum; //图的顶点数和弧数bool inq[MaxVertexNum]; //如果顶点i已入过,inq[i]==true。初值为falsevoid BFS(int u) { //遍历u所在的连通块queue<int> q; //定义队列qq.push(u); //初始顶点u入队inq[u] = true; //设置u已入过队while (!q.empty()) {u = q.front(); //取出队首元素并访问cout << vertices[u].data << "\t";q.pop(); //队首元素出队ArcNode *p = vertices[u].first;while (p) {if (inq[p->adjvex] == false) {q.push(p->adjvex);inq[p->adjvex] = true;}p = p->next;}}}public:ALGraph() {for (int i = 0; i < MaxVertexNum; i++) {inq[i] = false;vertices[i].first = NULL;}}void create() {int row, col;cin >> vexnum >> arcnum; //输入实际图的顶点数和边数for (int i = 0; i < vexnum; i++) //输入顶点信息cin >> vertices[i].data;for (int i = 0; i < arcnum; i++) { //输入边信息cin >> row >> col;ArcNode *p = new ArcNode;p->adjvex = col;p->next = vertices[row].first;vertices[row].first = p;}}void BFSTrave() { //遍历图Gfor (int u = 0; u < vexnum; u++) //枚举所有顶点if (inq[u] == false)BFS(u); //遍历u所在的连通块}
};int main() {ALGraph<string> G;G.create();G.BFSTrave();return 0;
}
四、广度优先遍历
深度优先搜索以“深度”作为第一关键词,每次都是沿着路径到不能再前进时才退回到最近的岔道口。以一个有向图(见下图)进行 DFS 遍历来举例(从V0 开始进行遍历,黑色表示结点未访问,白色表示结点已访问,虚线边表示当前遍历路径):
如果要遍历整个图,就需要对所有连通块(连通分量和强连通分量)分别进行遍历。所以 DFS 遍历图的基本思路就是将经过的顶点设置为已访问,在下次递归碰到这个顶点时就不再去处理,直到整个图的顶点都被标记为已访问。
#include <iostream>using namespace std;#define MaxVertexNum 100 //顶点数目的最大值struct ArcNode { //边表结点int adjvex; //该弧所指向的顶点的位置ArcNode *next; //指向下一条弧的指针
};template<typename VertexType>
struct VNode { //顶点表结点VertexType data; //顶点信息ArcNode *first; //指向第一条依附该顶点的弧的指针
};template<typename VertexType>
class ALGraph { //ALGraph是以邻接表存储的图类型
private:VNode<VertexType> vertices[MaxVertexNum]; //邻接表int vexnum, arcnum; //图的顶点数和弧数bool visited[MaxVertexNum]; //如果顶点i已被访问,则visited[i]==true。初值为falsevoid DFS(int u) { //u为当前访问的顶点索引cout << vertices[u].data << "\t";visited[u] = true; //设置u已被访问ArcNode *p = vertices[u].first;while (p) {if (visited[p->adjvex] == false)DFS(p->adjvex);p = p->next;}}public:ALGraph() {for (int i = 0; i < MaxVertexNum; i++) {visited[i] = false;vertices[i].first = NULL;}}void create() {int row, col;cin >> vexnum >> arcnum; //输入实际图的顶点数和边数for (int i = 0; i < vexnum; i++) //输入顶点信息cin >> vertices[i].data;for (int i = 0; i < arcnum; i++) { //输入边信息cin >> row >> col;ArcNode *p = new ArcNode;p->adjvex = col;p->next = vertices[row].first;vertices[row].first = p;}}void DFSTrave() { //遍历图Gfor (int u = 0; u < vexnum; u++) //对每个顶点uif (visited[u] == false) //如果u未被访问DFS(u); //访问u和u所在的连通块}
};int main() {ALGraph<string> G;G.create();G.DFSTrave();return 0;
}
邻接矩阵版:
#include <iostream>using namespace std;#define MaxVertexNum 100 //顶点数目的最大值// VertexType,顶点的数据类型
template<typename VertexType>
class MGraph {
private:VertexType Vex[MaxVertexNum]; //顶点表int Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵,边表int vexnum, arcnum; //图的当前顶点数和弧数bool visited[MaxVertexNum]; //如果顶点i已被访问,则visited[i]==true。初值为falsevoid DFS(int u) { //u为当前访问的顶点索引cout << Vex[u] << "\t";visited[u] = true; //设置u已被访问for (int i = 0; i < vexnum; i++)if (Edge[u][i] == 1 && visited[i] == false)DFS(i);}public:MGraph() {for (int i = 0; i < MaxVertexNum; i++) {visited[i] = false;for (int k = 0; k < MaxVertexNum; k++)Edge[i][k] = 0;}}void create() {int row, col;cin >> vexnum >> arcnum; //输入实际图的顶点数和边数for (int i = 0; i < vexnum; i++) //输入顶点信息cin >> Vex[i];for (int i = 0; i < arcnum; i++) { //输入边信息cin >> row >> col;Edge[row][col] = 1;}}void DFSTrave() { //遍历图Gfor (int u = 0; u < vexnum; u++) //对每个顶点uif (visited[u] == false) //如果u未被访问DFS(u); //访问u和u所在的连通块}
};int main() {MGraph<string> G;G.create();G.DFSTrave();return 0;
}
二、拓扑排序
拓扑排序就是对一个有向无环图构造拓扑序列的过程:
1、在有向图中选一个没有前驱的顶点并输出。
2、从图中删除该顶点和所有以它为尾的弧。
代码如下:
#include <bits/stdc++.h>
using namespace std;
#define MAXVERTIES 20
#define OK 1
#define ERROR 0int indegree[MAXVERTIES] = { 0 }; //用于存储入度信息/*
5
1 2 3 4 5
6
1 2
1 4
1 3
2 4
3 5
4 5
*///定义结点
struct VexNode {int data;VexNode *next;
};//定义弧
struct ArcNode {int data;VexNode *firstacr = NULL;
};//定义邻接表
struct GraphList {ArcNode arclist[MAXVERTIES];int vexnum, arcnum;
};//定义栈
struct Stack {int Sacklist[MAXVERTIES] = { 0 };int top = -1;
};//入栈操作
void Push(Stack &S, int key) {if (S.top == MAXVERTIES) {cout << "栈已满!" << endl;return;}S.top++;S.Sacklist[S.top] = key;
}//出栈操作
int Pop(Stack &S) {if (S.top == -1) {cout << "栈为空!" << endl;return -1;}int temp = S.Sacklist[S.top];S.top--;return temp;
}//返回结点在结点数组中的下标
int Location(GraphList &G, int key) {for (int i = 0; i < G.vexnum; i++) {if (G.arclist[i].data == key) {return i;}}return -1;
}//创建图
void CreatGraph(GraphList &G) {cout << "请输入顶点数:" << endl;cin >> G.vexnum;cout << "请输入顶点信息:" << endl;for (int i = 0; i < G.vexnum; i++) {cin >> G.arclist[i].data;}cout << "请输入弧数:" << endl;cin >> G.arcnum;cout << "请输入弧端点信息:" << endl;for (int i = 0; i < G.arcnum; i++) {int v1, v2;cin >> v1 >> v2;int Location1 = Location(G, v1);int Location2 = Location(G, v2);VexNode *new_node = new VexNode;new_node->data = Location2;new_node->next = G.arclist[Location1].firstacr;G.arclist[Location1].firstacr = new_node;indegree[Location2]++;}
}//拓扑排序
int TopoSort(GraphList &G, int *topolist) {Stack S;int topo = 0;//先将所有入度为0的结点入栈for (int i = 0; i < G.vexnum; i++) {if (indegree[i] == 0) {Push(S, i);}}//依次出栈入度为0的结点while (S.top != -1) {int vx = Pop(S);topolist[topo++] = G.arclist[vx].data; //输出结点VexNode *temp = G.arclist[vx].firstacr;//删除以该结点为尾的弧while (temp != NULL) {int index = temp->data;indegree[index]--; //将该弧的弧头结点入度减1//如果入度为0,则入栈if (indegree[index] == 0) {Push(S, index);}temp = temp->next;}}topolist[topo] = -1;//如果拓扑序列中的元素个数等于所有元素个数,则该图无环,否则该图有环if (topo == G.vexnum) {return OK;} else {return ERROR;}
}int main() {GraphList GL;CreatGraph(GL);int topolist[MAXVERTIES] = { 0 };int vx = TopoSort(GL, topolist);if (!vx) {cout << "有环!" << endl;} else {cout << "有向无环!" << endl;cout << "拓扑序列如下:" << endl;for (int i = 0; topolist[i] != -1; i++) {cout << topolist[i] << " ";}}return 0;
}