头文件:Graph.h
#ifndef GRAPH_H
#define GRAPH_H#pragma once
#include <vector>
#include <iostream>
#include <fstream>
using namespace std;
typedef vector<vector<int> > Myarray2;
typedef struct
{
int begin;
int end;
int weight;
}Edge;
class Graph
{
public:
Graph(int num1,int num2):m_VertexNum(num1),m_EdgeNum(num2){};
virtual ~Graph(void){};
bool Initialization(const char *);
void Dijkstra(int index,int *,int*,bool*);//点index到途中各点的最短路径
void Floyd(void);//图中每个点到另外各点的最短路径
void Prim(int *,int *);//找连通图的最小生成树
void Kruskal(int *);
void print(void);
void DFS(bool*,int i);
void DFSTraverse(bool *);
void BFSTraverse(bool *);
private:
int m_EdgeNum;
int m_VertexNum;
Myarray2 m_AdjArray;
vector<Edge> edges;
};
#endif
#include "Graph.h"
#include <vector>
#include<queue>
using namespace std;
void Graph::print()
{
for (int i = 0;i<m_VertexNum;++i)
{
for(int j = 0;j<m_VertexNum;++j)
cout<<m_AdjArray[i][j]<<' ';
cout<<endl;
}
}
///从图文件中读入图的信息,初始化邻接矩阵和边集
bool Graph::Initialization(const char * filename)
{
Edge e;
ifstream infile1(filename,ios::in);
if (!infile1)
{
cerr<<"open error!"<<endl;
return false;
}
for (int i=0;!infile1.eof();++i)
{
int a;
vector<int> temp;
for (int j = 0;j<m_VertexNum;++j)
{
infile1>>a;
temp.push_back(a);
if(a != 65535 && j>i)
{
e.begin = i;
e.end = j;
e.weight = a;
edges.push_back(e);
}
}
m_AdjArray.push_back(temp);
}
//此时得到的边集edges是未经过排序的
//下面对边集进行排序
bool exchage = true;
for(int i = 1;i<m_EdgeNum && exchage;++i)
{
exchage = false;
for (int j = m_EdgeNum-1;j>i ;j--)
{
if (edges[j].weight < edges[j-1].weight)
{
//cout<<edges[j].weight<<" "<<edges[j-1].weight;
swap(edges[j],edges[j-1]);
exchage = true;
}
}
}
return true;
}
void Graph::Dijkstra(int index,int *dis,int * prevertex,bool* visit)
{
int k = 0;//记录每次比较中的最小点
//初始化距离向量dis,前驱向量prevertex,访问向量visit
//dis[i]保存的是从index点到i点的最短路径长度
//prevertex[i]保存的是从index点到i点的最短路径到达i点的上一步经过的是哪个点
for (int v = 0;v<m_VertexNum;++v)
{
dis[v] = m_AdjArray[index][v];
prevertex[v] = index;
visit[v] = false;
}
//源点的visit设为true/////////
visit[index] = true;
//开始循环
for(int v = 0;v<m_VertexNum;v++)
{
int min = INT_MAX;
//dis里寻找离index最近的点,其点标号为k
//即寻找目前dis里最小的值
for(int w = 0;w<m_VertexNum;w++ )
{
//只在未访问过的点里找(此时index已经访问了,所以满足visit[w]=false的点一定有w!=index)
while(!visit[w] && dis[w]<min )
{
k = w;//最小点对应位置为k
min = dis[w];
}
}
//将最近点k点的访问标志记为true
visit[k] = true;
//检查是否需要更改距离表dis,即是否有dis[w]>dis[k]+m_AdjArray[k][w]
//此时距离表中存储的是index点直接或经过已访问点到各点的最短路径长度
for (int w = 0;w<m_VertexNum;++w)
{
if (!visit[w] && dis[w] > dis[k] +m_AdjArray[k][w])
{
dis[w] = dis[k] +m_AdjArray[k][w];
prevertex[w] = k;
}
}
//}
}
//算法完毕,输出
//此时dis[i]保存的是从index点到i点的最短路径长度
//prevertex[i]保存的是从index点到i点的最短路径到达i点的上一步经过的是哪个点
printf("距离向量为:\n");
for (int i = 0;i<m_VertexNum;++i)
{
printf("%d ",dis[i]);
}
printf("\n前驱向量为:\n");
for (int i = 0;i<m_VertexNum;++i)
{
printf("%d ",prevertex[i]);
}
printf("\n");
for (int v = 0;v<m_VertexNum;++v)
{
int p = v;
printf("顶点%d到顶点%d的最短路径为:\n%d<--",index,v,v);
while(prevertex[p] != index)
{
printf("%d<--",prevertex[p]);
p = prevertex[p];
}
printf("%d\n",index);
}
}
void Graph::Floyd(void)
{
//初始化路线矩阵
Myarray2 path;//path[v][w]表示从v到w的最短路径必须先经过path[v][w]点(前驱)
Myarray2 adarr;//
for (int i=0;i<m_VertexNum;++i)
{
vector<int> temp;
for (int j = 0;j<m_VertexNum;++j)
{
temp.push_back(j);
}
path.push_back(temp);
}
//开始循环
for (int k = 0;k<m_VertexNum;++k)//表示从k中转即观察是否有m_AdjArray[v][w] > m_AdjArray[v][k]+m_AdjArray[k][w]
{
for (int v = 0;v<m_VertexNum;++v)
{
for (int w =0;w<m_VertexNum;++w)
{
if(m_AdjArray[v][w] > m_AdjArray[v][k]+m_AdjArray[k][w])
{
m_AdjArray[v][w] = m_AdjArray[v][k]+m_AdjArray[k][w];
path[v][w] = path[v][k];
}
}
}
}
//算法完毕,输出
//此时m_AdjArray[v][w]表示从v到w的最短路径长度(已经不是最初的m_AdjArray了)
//path[v][w]表示从v到w的最短路径的要先经过path[v][w]点(前驱)
for(int v = 0;v<m_VertexNum;++v)
{
for (int w = 0;w<m_VertexNum;++w)
{
printf("从%d到%d的最短路径为:\n%d->",v,w,v);
int temp = path[v][w];
while(temp!=w)
{
printf("%d->",temp);
temp = path[temp][w];
}
printf("%d\n该路径长度为%d\n",w,m_AdjArray[v][w]);
}
}
}
void Graph::Prim(int *lowcost,int * prevertex)
{
int result = 0;//记录最小生成树总长度
for (int i = 0;i < m_VertexNum;++i)
{
lowcost[i] = m_AdjArray[0][i];//初始化lowcost向量,lowcost[i]表示从所有已选点到第i个点的直接最短距离为lowcost[i]
prevertex[i] = 0;//初始化prevertex向量,prevertex[i]表示所有已选点中prevertex[i]点到第i个点的直接距离最短
}
printf("最小生成树如下:\n");
for (int i = 1;i < m_VertexNum;++i)//除了初始点,循环m_VertexNum-1次,保证最终所有点都被遍历到
{
int min = INT_MAX;
int k = 0;
int num = 1;
//每次找lowcost向量中的最小值
while (num < m_VertexNum)
{
if (lowcost[num] != 0 && lowcost[num] < min)
{
min = lowcost[num];
k = num;
}
++num;
}
result += lowcost[k];
printf("%d->%d:length is:%d\n",prevertex[k],k,lowcost[k]);
lowcost[k] = 0;//表示从已选点到k的最小距离为0即将点k加入已选点
//由新加入的已选点更新lowcost和prevertex向量
//即观察对于所有未选点(lowcost[j] != 0),是否有lowcost[j] > m_AdjArray[k][j]
//若有,则将相应的prevertex置为k
for (int j = 1;j < m_VertexNum;++j)
{
if (lowcost[j] != 0 &&lowcost[j] > m_AdjArray[k][j])
{
lowcost[j] = m_AdjArray[k][j];
prevertex[j] = k;
}
}
}
printf("最小生成树总长度为:%d\n",result);
}
int findParent(int *parent,int f)
{
while (parent[f]>0)
{
f = parent[f];
}
return f;
}
void Graph::Kruskal(int *parent)
{
int m,n;
//*****初始化数组值为0
memset(parent,0,sizeof(int)*m_EdgeNum);
for (int i = 0;i<m_EdgeNum;++i)
{
m = findParent(parent,edges[i].begin);
n = findParent(parent,edges[i].end);
//*****若m与n不相等,说明此边没有与现成生成树形成回路
if (m!=n)
{
parent[m] = n;//将此边的结尾结点放入下标为起点的parent中
//parent中可达的结点表示最大的不连通的边集合
printf("(%d,%d) %d\n",edges[i].begin,edges[i].end,edges[i].weight);
}
}
}
void Graph::DFS(bool visit[],int i){
visit[i] = true;
printf("%d ",i);
for (int j = 0;j<m_VertexNum;++j)
{ //cout<<m_AdjArray[i][j];
if(m_AdjArray[i][j] != 65535 && !visit[j])
DFS(visit,j);
}
}
void Graph::DFSTraverse(bool visit[]){
//初始化访问矩阵
for(int i = 0;i<m_VertexNum;++i)
visit[i] = false;
for(int i = 0;i<m_VertexNum;++i)
{
if(!visit[i])//对未访问的顶点调用DFS,如果是连通图,只会执行一次
DFS(visit,i);
}
}
void Graph::BFSTraverse(bool visit[]){
//初始化访问矩阵
for(int i = 0;i<m_VertexNum;++i)
visit[i] = false;
queue<int> vertex;
for (int i = 0;i<m_VertexNum;++i)
{
if (!visit[i])
{
visit[i] = true;
printf("%d ",i);
vertex.push(i);
while(!vertex.empty())
{
i = vertex.front();
vertex.pop();
for (int j = 0;j<m_VertexNum;++j)
{
if (m_AdjArray[i][j] != 65535 && !visit[j])
{
printf("%d ",j);
vertex.push(j);
visit[j] = true;
}
}
}
}
}
}