邻接矩阵
(1)顶点表 (2)邻接矩阵
DFS的递归非递归,BFS的非递归(队列)
权重分有向图和无向图。
无向图的初始化可以全为0
有向图的初始化对角线为0,其他为正无穷
#include<iostream>
#include"Queue.h"
#include "Minheap.h"
using namespace std;
//图的邻接矩阵模式
extern const int maxWeight=9999;
const int maxSize = 100;
//邻接矩阵存储的图的类定义(无向图)
template <class T, class E>
class Graphmtx //图的邻接矩阵类定义
{
friend istream& operator >>(istream& in, Graphmtx<T, E>& G);
friend ostream& operator <<(ostream& out, Graphmtx<T, E>& G);
public:
int maxWeightG;
Graphmtx(int sz); //构造函数
~Graphmtx() //析构函数
{
delete[]VertexList;
delete[]Edge;
}
T getValue(int i) //取顶点i的值, i不合理返回0
{
return i >= 0 && i < numVertices ? VertexList[i] : 0;
}
E getWeight(int v1, int v2) //取边(v1,v2)上的权值,若边不合理,则返回0
{
return v1 != -1 && v2 != -1 ? Edge[v1][v2] : 0;
}
//取顶点v的第一个邻接顶点//返回该邻接顶点的编号,若不存在则返回-1
int getFirstNeighbor(int v)
{
if (v<0 || v>numVertices) { cout << "下标有误,不存在该顶点"; return -1; }//不存在该顶点
for (int i = 0; i < numVertices; i++)
{
if (Edge[v][i] > 0 && Edge[v][i] < 9999)
{
return i;
}
}
}
//取v的邻接顶点w的下一邻接顶点//返回下一个邻接定点的编号,若不存在或参数不合理则返回-1
int getNextNeighbor(int v, int w)
{
if (v != -1 && w != -1)
{
for (int col = w + 1; col < numVertices; col ++)
{
if (Edge[v][col] > 0 && Edge[v][col] < 9999)
{
return col;
}
}
}
}
//插入顶点vertex
bool insertVertex(const T& vertex)
{ //接受一个参数,表示插入顶点的值,返回true表示插入成功
if (numVertices == maxVertices) return false;
VertexList[numVertices++] = vertex;
return true;
}
//插入边(v1, v2),权值为cost//返回true表示插入成功
bool insertEdge(int v1, int v2, E cost)
{
if (v1 > -1 && v1 < numVertices && v2>-1 && v2 < numVertices && Edge[v1][v2] == maxWeight)
{
Edge[v1][v2] = cost;
numVertices++;
return true;
}
else
return false;
}
//删去顶点v和所有与它相关联的边
bool removeVertex(int v)
{
if (v<0 || v>maxWeight) return false;
if (numVertices == 1) return false;
int i = 0,j=0;
for (i = 0; i < numVertices; i++) //减去有关的边
{
if (Edge[i][v] > 0 && Edge[i][v] < maxWeight) numEdges--;
}
//用最后一个顶点覆盖要移除的顶点
for (i = 0; i < numVertices; i++)
{
Edge[i][v] = Edge[i][numVertices - 1];//用最后一列填补删除的那一列
}
for (j = 0; j < numVertices; j++)
{
Edge[v][j] = Edge[numVertices - 1][j];//用最后一行填补删除的那一行
}
return true;
}
//在图中删去边(v1,v2)
bool removeEdge(int v1, int v2)
{
if (v1 > -1 && v1 < numVertices && v2>-1 && v2 < numVertices && Edge[v1][v2] < maxWeight && Edge[v1][v2] > 0)
{
Edge[v1][v2] = Edge[v2][v1] = maxWeight;
numEdges--;
return true;
}
else
return false;
}
int NumberofVertices()
{
return numVertices;
}
int NumberofEdges()
{
return numEdges;
}
int getVertexPos(const T& vertex) //给出顶点vertex在图中的位置,若不存在则返回-1
{
for (int i = 0; i < numVertices; i++)
{
if (VertexList[i] == vertex)
{
return i;
}
}
return -1;
}
void DFS(Graphmtx<T, E> &G, int v);
void BFS(Graphmtx<T, E>& G, int k);
void locata( T& vex1, T& vex2, int& m, int& n);
void getGraphmtx();
private:
int maxVertices; //图中最大顶点数
int numEdges;
int numVertices;
int getVertexPos(T vertex) //找到顶点的位置。可以优化成散列的方式找该顶点,效率更高
{
for (int i = 0; i < numVertices; i++)
{
if (VertexList[i] == vertex) return i;
}
return -1;
}
T* VertexList; //顶点表(点集)
E** Edge; //邻接矩阵, 数组的元素值为两个顶点之间的权值。(边集)
bool *visited; //遍历标记
};
template <class T, class E>
istream& operator >>(istream& in, Graphmtx<T, E>& G)
{
int i = 0, j = 0, k = 0, n = 0, m = 0;
E weight; //权重
T e1, e2; //顶点
cout << "输入顶点数和边数" << endl;
in >> n >> m; //输入顶点数和边数
for (i = 0; i < n; i++)
{
cin >> e1; G.insertVertex(e1);
}
i = 0;
while (i < m)
{
cout << "请输入两个顶点以及顶点之间的权重" << endl;
in >> e1 >> e2 >> weight;
j = G.getVertexPos(e1); k = G.getVertexPos(e2);
if (j == -1 || k == -1)
{
cout << "边的两端点信息有误" << endl;
}
else
{
G.insertEdge(j, k, weight);
i++;
}
}
return in;
}
template <class T, class E>
ostream& operator <<(ostream& out, Graphmtx<T, E>& G)
{
int i = 0, j = 0, k = 0, n = 0, m = 0;
E weight; //权重
T e1, e2; //顶点
n = G.NumberofVertices();
m = G.NumberofEdges();
out << "顶点数 " << n << "," << " 边数 " << m <<endl;
for (i = 0; i < n; i++)
{
for (j = i + 1; j < n; j++)
{
weight = G.getWeight(i, j);
if (weight > 0 && weight < maxWeight)
{
e1 = G.getValue(i);
e2 = G.getValue(j);
out << "(" << e1 << "," << e2 << ")" << endl;
}
}
}
return out;
}
//构造函数
template <class T, class E>
Graphmtx<T, E>::Graphmtx(int sz)
{
int i = 0, j = 0;
maxVertices = sz;
maxWeightG = maxWeight;
numVertices = 0; //初始化顶点数为0,后面加入时会累次递增
numEdges =0;
cout << "请输入顶点的数量" << endl;
cin >> numVertices;
VertexList = new T[maxVertices]; //顶点只需要一维的矩阵存就可以。
Edge = (int**) new int* [maxVertices]; //创建邻接矩阵数组
visited = new bool[maxVertices];
for (i = 0; i < numVertices; i++)
{
cin >> VertexList[i];
}
for (i=0;i< maxVertices;i++)
{
visited[i] = false;
}
for (i = 0; i < maxVertices; i++)
{
Edge[i] = new int[maxVertices];
}
for (i = 0; i < maxVertices; i++)//浪费空间的做法,需要一开始就开很大的空间。
{
for (j = 0; j < maxVertices; j++)
{
Edge[i][j] = (i == j) ? 0 : maxWeight; //除了对角线为0,其余都是无穷大(权值)带权图
//不带权的图可以直接全部初始化为0
}
}
getGraphmtx();
}
//创建图(以邻接矩阵的方式)
//通过结点信息(A,B,C,D之类)来查找对应矩阵下标
//确定边在矩阵的位置
template <class T, class E>
void Graphmtx<T, E>::locata( T& vex1, T& vex2, int& m, int& n)
{
for (int i = 0; i < maxVertices; i++)
{
if (vex1 == VertexList[i])
m = i;
if (vex2 == VertexList[i])
n = i;
}
}
//创建图对应的邻接矩阵
template <class T, class E>
void Graphmtx<T, E>::getGraphmtx()
{
E weight;
//根据输入的两个顶点,来更新矩阵的值(如输入A,B表示从A到B有一条边,就更新矩阵相应位置的值为1)
int i = 1;
while(i<=numVertices)
{
T vex1, vex2; //接受输入的两个顶点,来表示从vex1到vex2这条边
cout << "请输入边的信息(形如A B,表示从A到B的一条边)以及权重:";
cin >> vex1 >> vex2>>weight;
int m = 0, n = 0; //m和n是用来接受vex1和vex2所在的下标值,好据此更新矩阵相应位置的值
locata(vex1, vex2, m, n);
Edge[m][n] = weight;
Edge[n][m] = weight;//无向图邻接矩阵对称,少掉这句代码就是有向图的邻接矩阵了
i++;
}
}
template <class T, class E>
void Graphmtx<T, E>::DFS(Graphmtx<T, E> &G, int v) //输入图,和当前顶点的位置
{
int j = 0;
G.visited[v] = true;
cout << G.VertexList[v]<<"-> ";
for (j = 0; j < G.numVertices; j++)
if (G.Edge[v][j]>0&&G.Edge[v][j]<maxWeightG && !visited[j]) //v表示其中一个点的下标为(0-4),j表示另一个点的下标为(0-4)
//该判断是邻接点 且未被访问过的点
DFS(G, j);
}
template <class T, class E>
void Graphmtx<T, E>::DFS2(Graphmtx<T, E>& G, int num)
{
Stack<int> st;
G.visited[num] = true;
st.Push(num);
while (!st.Isempty())
{
st.getTop(num);
st.Pop(num);
cout << G.VertexList[num] << " " << endl;
for (int j = G.numVertices - 1; j >= 0 ; j--) //找邻接点
if (G.Edge[num][j] > 0 && G.Edge[num][j] < maxWeightG && !visited[j])
{
st.Push(j);
G.visited[j] = true;
}
}
setvisited(); //为了访问
}
/*
//这个是邻接表的遍历递归,需要参数v的
//DFS=====类似前序遍历,就可以看成前序遍历(根左右)
template<class T, class E>
void Graph<T, E>::DFS(int v) //v表示起点
{
Edge<T, E> *p;
visited[v] = true;
cout << NodeTable[v].data<<" -> ";
p = NodeTable[v].adj;
while (p != 0)
{
if (!visited[p->dest])
DFS(p->dest);//先把一个点的路走到头, 再找其他点作为起点
p = p->link;
}
}
*/
//BFS用队列
//图可以看成n叉树,每一层都可以有n个子结点
//每次调用函数前都要设置visited矩阵为0
template <class T, class E>
void Graphmtx<T, E>::BFS(Graphmtx<T, E>& G, int k) //输入图,和当前顶点的位置
{
int i = 0;
for (i = 0; i < maxVertices; i++)
{
visited[i] = false;
}
SeqQueue<int> q;
q.EnQueue(k);
G.visited[k]= 1;
i = 0;
while (!q.IsEmpty())
{
i = q.getFront(i);
q.DeQueue(i);
cout << G.VertexList[i] << "-> ";
for (int j = 0; j < G.numVertices; j++) {
if (G.Edge[i][j]>0&& G.Edge[i][j]<maxWeightG && G.visited[j] == 0)//把所有子结点入队(或者理解为把所有相邻结点且未访问过的入队)
{
G.visited[j] = 1;
q.EnQueue(j);
}
}
}
}