一、图的邻接矩阵存储 AMGraph
/*有向图的邻接矩阵存储*/
#define maxValue 999 //表示正无穷
#define MVNum 100 //矩阵的最大空间为100*100
typedef char verTextType; //顶点数据类型
typedef int ArcType; //边的权值
typedef struct{
verTextType vexs[MVNum]; //顶点集用一个数组表示
ArcType arcs[MVNum][MVNum]; //边集用一个二维矩阵表示
int vexnum, arcnum; //图的顶点数,边数
}AMGraph;
int Location(AMGraph G, verTextType v) //顶点v在顶点集数组中的索引
{
for(int i = 0; i < G.vexnum; i++)
if(G.vexs[i] == v)
return i;
return -1; //顶点集中没有顶点v
}
void Create(AMGraph &G)
{
cout << "输入顶点数: ";
cin >> G.vexnum;
cout << "输入边数: ";
cin >> G.arcnum;
cout << "输入全部的顶点: ";
for(int i = 0; i < G.vexnum; i++)
cin >> G.vexs[i];
for(int i = 0; i < G.vexnum; i++) //初始化所有边的权值
{
for(int j = 0; j < G.vexnum; j++)
G.arcs[i][j] = maxValue;
}
verTextType Start, End; //接收边的起点,接收边的终点
for(int i = 0; i < G.arcnum; i++)
{
cout << "输入第" << i+1 << "条边的起点:";
cin >> Start;
cout << "输入第" << i+1 << "条边的终点:";
cin >> End;
int index1 = Location(G,Start);
int index2 = Location(G,End); //利用location函数得到起点和终点在顶点数组中的位置
cout << "输入第" << i+1 << "条边的权值:";
cin >> G.arcs[index1][index2]; //利用上一步的的两个索引值确定边的位置
}
}
void TestFun(AMGraph G) //测试create函数
{
cout<<"邻接矩阵如下:" << endl;
for(int i = 0; i < G.vexnum; i++)
{
for(int j = 0; j < G.vexnum; j++)
cout << G.arcs[i][j] << " ";
cout << endl;
}
}
int main()
{
AMGraph* P1 = new AMGraph;
Create(*P1);
TestFun(*P1);
return 0;
}
二、图的邻接表存储 ALGraph
/*图有向图的邻接表存储*/
#define MVnum 100 //最大顶点数
typedef char VerTexType; //顶点数据类型
typedef int OtherInfo; //其他信息,如权值
typedef struct ArcNode //定义边结点
{
int adjvex; //该边指向的顶点的位置(索引)
struct ArcNode *nextarc; //指向下一条边的指针
OtherInfo info; //其他信息,如边的权值
}ArcNode;
typedef struct VNode //定义表头结点
{
VerTexType data; //顶点的名称
ArcNode *firstarc; //指针指向以该顶点作为起点的第一条边的结点
}VNode,AdjList[MVnum]; //AdjList表示邻接表类型:实际上邻接表是由一组单链表组成的;
//其中,表头结点表是一个一维数组,它的每个元素是一个表头结点;
//每一个表头结点作为单链表的表头,和几个边结点组成了一个单链表。
typedef struct //定义邻接表
{
AdjList vertices; //邻接表,表头结点数组
int vexnum, arcnum; //图的当前顶点和边数
}ALGraph;
int Location(ALGraph G, VerTexType v) //确定顶点v在顶点集数组中的索引
{
for(int i = 0; i < G.vexnum; i++)
if( G.vertices[i].data == v )
return i;
return -1;
}
void Create(ALGraph &G)
{
cout << "输入顶点个数: ";
cin >> G.vexnum;
cout << "输入边的条数: ";
cin >> G.arcnum;
cout << "输入全部顶点: ";
for(int i = 0; i < G.vexnum; i++)
{
cin >> G.vertices[i].data;
G.vertices[i].firstarc = NULL; //初始化顶点指向的第一条边
}
for(int j = 0; j < G.arcnum; j++)
{
VerTexType Start, End;
cout << "输入第" << j+1 << "条边的起点:";
cin >> Start;
cout << "输入第" << j+1 << "条边的终点:";
cin >> End;
int index1 = Location(G, Start); //得到起点的位置
int index2 = Location(G, End); //得到终点的位置
ArcNode* new_arc = new ArcNode; //为这条边申请一个节点空间
cout << "输入第" << j+1 << "条边的权值:";
cin >> new_arc->info;
new_arc->adjvex = index2; //存储终点的位置(索引)
new_arc->nextarc = G.vertices[index1].firstarc; //利用尾插法,将该结点插入起点后面
G.vertices[index1].firstarc = new_arc;
}
}
void TestFun(ALGraph G)
{
cout << "邻接矩阵如下:" << endl;
for(int i = 0; i < G.vexnum; i++)
{
cout << i << " " << G.vertices[i].data << "->";
ArcNode * p = G.vertices[i].firstarc;
while(p)
{
cout << p->adjvex << "(终点)" << p->info << "(权值)" << "->";
p = p->nextarc;
}
cout << endl;
}
}
int main()
{
ALGraph* P2 = new ALGraph;
Create(*P2);
TestFun(*P2);
return 0;
}
三、图的深度优先遍历(AMGraph)
/*图的深度优先遍历*/
bool visited[MVNum]; //用来记录顶点是否已被访问
void DFS_connected(AMGraph G, int v) //深度优先遍历邻接矩阵存储的连通图,v为遍历的起点的位置
{
cout << G.vexs[v] << " "; // 起点最先被访问,输出起点
visited[v] = true;
for(int w = 0; w < G.vexnum; w++) //设计递归算法:找到未被访问的以V为起点,w为终点的边,并将w作为下一次操作的起点
if((G.arcs[v][w] != maxValue) && (!visited[w]))
DFS_connected(G,w);
}
void DFS(AMGraph G) //深度优先遍历邻接矩阵存储的非连通图
{
for(int m = 0; m < G.vexnum; m++) //初始化数组
visited[m] = false;
for(int m = 0; m < G.vexnum; m++)
if(!visited[m])
DFS_connected(G,m); //在每个"划分"里调用DFS_connected函数,默认从第一个顶点开始遍历
}
int main()
{
AMGraph* P1 = new AMGraph;
Create(*P1);
cout << "深度优先遍历顺序:";
DFS(*P1);
return 0;
}
三、图的深度优先遍历(ALGraph)
#define MVnum 100
bool visited[MVnum];
void DFS_connected(ALGraph G, int v) //邻接表存储的连通图
{
cout << G.vertices[v].data << " "; //输出顶点
visited[v] = true;
ArcNode *p = G.vertices[v].firstarc;
while(p != NULL)
{
int w = p->adjvex;
if(!visited[w])
DFS_connected(G,w);
p = p->nextarc;
}
}
void DFS(ALGraph G)
{
for(int v = 0; v < G.vexnum; ++v)
visited[v] = false;
for(int v = 0; v < G.vexnum; ++v) //遍历的起点为输入的第一个顶点
if(!visited[v])
DFS_connected(G, v);
}
int main()
{
ALGraph* P2 = new ALGraph;
Create(*P2);
TestFun(*P2);
DFS(*P2);
return 0;
}
四、图的广度优先遍历(AMGraph)
#include <iostream>
#include <queue>
using namespace std;
#define maxValue 999 //表示正无穷
#define MVNum 100 //矩阵的最大空间为100*100
typedef char verTextType; //顶点数据类型
typedef int ArcType; //边的权值
typedef struct{
verTextType vexs[MVNum]; //顶点集用一个数组表示
ArcType arcs[MVNum][MVNum]; //边集用一个二维矩阵表示
int vexnum, arcnum; //图的顶点数,边数
}AMGraph;
int Location(AMGraph G, verTextType v) //顶点v在顶点集数组中的索引
{
for(int i = 0; i < G.vexnum; i++)
if(G.vexs[i] == v)
return i;
return -1; //顶点集中没有顶点v
}
void Create(AMGraph &G)
{
cout << "输入顶点数: ";
cin >> G.vexnum;
cout << "输入边数: ";
cin >> G.arcnum;
cout << "输入全部的顶点: ";
for(int i = 0; i < G.vexnum; i++)
cin >> G.vexs[i];
for(int i = 0; i < G.vexnum; i++) //初始化所有边的权值
{
for(int j = 0; j < G.vexnum; j++)
G.arcs[i][j] = maxValue;
}
verTextType Start, End; //接收边的起点,接收边的终点
for(int i = 0; i < G.arcnum; i++)
{
cout << "输入第" << i+1 << "条边的起点:";
cin >> Start;
cout << "输入第" << i+1 << "条边的终点:";
cin >> End;
int index1 = Location(G,Start);
int index2 = Location(G,End); //利用location函数得到起点和终点在顶点数组中的位置
cout << "输入第" << i+1 << "条边的权值:";
cin >> G.arcs[index1][index2]; //利用上一步的的两个索引值确定边的位置
}
}
bool visited[MVNum]; //该数组的大小为MVNum,用于AMGraph
int FirstAdjVex(AMGraph G,int u)
{
for(int i = 0; i < G.vexnum; ++i)
if(G.arcs[u][i] != maxValue) //得到以u为起点的第一个未被访问的终点的位置
return i; //返回u作为起点的边的第一个终点的位置,如果没有则返回-1
return -1;
}
int NextAdjVex(AMGraph G,int u,int w) //得到以u作为起点,w作为相邻的上一个终点的终点的位置
{
for(int i = w+1 ; i < G.vexnum; ++i)
if(G.arcs[u][i] != maxValue) //得到w的下一个终点的位置,如果没有则返回-1
return i;
return -1;
}
void BFS_connected(AMGraph G,int v) //广度优先遍历【邻接矩阵存储】的连通图,v表示遍历的起点的位置
{
cout << "->" << G.vexs[v]; //输出起点
visited[v] = true;
queue<verTextType> Q; //利用队列按顺序存储访问点,类似于层序遍历; 使用该数据类型需要 #include <queue>
Q.push(G.vexs[v]); //让起点入队
while(!Q.empty())
{
int u = Location(G, Q.front()); //获取队头顶点的位置作为下一层遍历的起点,并让队头顶点出队
Q.pop();
for(int w = FirstAdjVex(G,u); w >= 0; w = NextAdjVex(G,u,w)) //依次输出以u(刚刚出队的原队头顶点)为起点的终点并让他们入队
{
if(!visited[w])
{
cout << "->" << G.vexs[w];
visited[w] = true;
Q.push(G.vexs[w]);
}
}
}
}
void BFS(AMGraph G) //广度优先遍历【邻接矩阵存储】的【非连通图】
{
for(int v = 0; v < G.vexnum; ++v)
visited[v] = false;
for(int v = 0; v < G.vexnum; ++v)
if(!visited[v])
BFS_connected(G, v);
}
int main()
{
AMGraph* P1 = new AMGraph;
Create(*P1);
cout << "广度优先遍历:" << endl;
BFS(*P1);
return 0;
}
五、Dijkstra算法求图的最短路径(AMGraph)
/*对于邻接矩阵存储的图,使用Dijkstra算法求最短路径*/
void ShortestPath_DIJ(AMGraph G,int v0)
{
int n = G.vexnum;
bool S[n]; //记录顶点是否访问
int D[G.arcnum]; //记录权值
int Path[G.vexnum]; //记录最短路径到该点的上一个顶点
int ShowPath[G.vexnum];
for(int v = 0; v < n; ++v) //找到所有与v0连接的顶点
{
S[v] = false;
D[v] = G.arcs[v0][v];
if(D[v] < maxValue)
Path[v] = v0;
else
Path[v] = -1;
}
S[v0] = true;
D[v0] = 0;
for(int i = 1; i < n; ++i)
{
int min = maxValue;
int v;
for(int w = 0; w < n; ++w)
{
if(!S[w] && D[w] < min)
{
v = w;
min = D[w];
}
}
S[v] = true;
for(int w = 0; w < n; ++w)
{
if(!S[w] && (D[v] + G.arcs[v][w] < D[w]))
{
D[w] = D[v] + G.arcs[v][w];
Path[w] = v;
}
}
}
cout << "得到的最短路径表:" << endl;
for(int i = 0; i < G.vexnum; i++)
{
if(Path[i] != -1)
cout << G.vexs[i] << "的前一个点是"<< G.vexs[Path[i]] << endl;
else
cout << "起点和" << G.vexs[i] << "之间不存在最短路径" << endl;
}
}
int main()
{
AMGraph* P1 = new AMGraph;
Create(*P1);
TestFun(*P1);
cout << "输入最短路径的起点:";
verTextType v0;
cin >> v0;
ShortestPath_DIJ(*P1,Location(*P1, v0));
return 0;
}