无向图的邻接矩阵实现--12月8日--12月29日改

邻接矩阵

(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);                                                            
			}
		}
	}
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值