【图】邻接矩阵

        图的存储结构分为邻接矩阵和邻接表两种,带权的图叫做网。

邻接矩阵

        邻接矩阵适合边多的图

 无向图

        两个顶点之间的连线是双向的,一个一维数组存顶点,一个二维数组存边

若有边则值为1,反之为0

        邻接矩阵需要知道点数、边数、一个二维数组存边、一个指针指向点,一个规定最多存放顶点数的值。

#define SIZE 10
class Graph
{
	int m_MaxVertex;//最大顶点个数
	int m_NumVertex;//实际顶点个数
	int m_NumEdge;//边数
	char* m_VertexArr;//存顶点
	int m_Edge[SIZE][SIZE];//存边

public:
	Graph();//构造
	~Graph();//析构
	void InsertVertex(char v);//插入点
	void InsertEdge(char v1, char v2);//在点v1和v2之间插入边
	void PrintGraph();//输出
	int GetVertexIndex(char v);//获取下标
	void DeleteEdge(char v1, char v2);//删除边
	void DeleteVertex(char v);//删除点
};

构造和析构函数

Graph::Graph()
{
	m_MaxVertex = SIZE;//设置最大的顶点数
	m_NumVertex = m_NumEdge = 0;//初始为0
	for (int i = 0; i < m_MaxVertex; i++)
	{
		for (int j = 0; j < m_MaxVertex; j++)
			m_Edge[i][j] = 0;
	}
	m_VertexArr = new char[m_MaxVertex];//m_VertexArr指向装顶点的数组
}
Graph::~Graph()
{
	if (m_VertexArr != nullptr)
	{
		delete[]m_VertexArr;
		m_VertexArr = nullptr;
	}
	m_NumEdge = m_NumVertex = 0;
}

插入顶点

如果顶点数大于最多能存的顶点数,直接返回

否则存入存顶点的数组m_VertexArr,实际顶点数m_NumVertex++

//插入顶点
void Graph::InsertVertex(char v)
{
	if (m_NumVertex >= m_MaxVertex)
	{
		return;
	}
	m_VertexArr[m_NumVertex++] = v;
}

得到一个顶点的下标

从第一个遍历到最后一个,若找到了,返回下标;若没找到,返回-1。

//得到下标
int Graph::GetVertexIndex(char v)
{
	for (int i = 0; i < m_NumVertex; i++)
	{
		if (v == m_VertexArr[i])
		{
			return i;
		}
	}
	return -1;
}

插入边

        在v1和v2两个顶点之间插入边:

首先找到两个顶点的下标;

若找到,使其存边数组中值等于1,因为是无向图,所以要m_Edge[p1][p2] = m_Edge[p2][p1]=1;

边数++

//插入边
void Graph::InsertEdge(char v1, char v2)
{
	int p1 = GetVertexIndex(v1);
	int p2 = GetVertexIndex(v2);
	if (p1 == -1 || p2 == -1)return;

	m_Edge[p1][p2] = m_Edge[p2][p1]=1;
	m_NumEdge++;
}

删除边

        与插入边类似。

//删边
void Graph::DeleteEdge(char v1, char v2)
{
	int p1 = GetVertexIndex(v1);
	int p2 = GetVertexIndex(v2);
	if (p1 == -1 || p2 == -1)return;

	m_Edge[p1][p2] = m_Edge[p2][p1] = 0;
	m_NumEdge--;
}

删除点

方法1:直接删

        这个方法比较麻烦,要将点、边数组中该点后面的数据全部往前移,如果边多不适合该方法

1.找下标,2.求相连边数,3.删点,4.删边行列(出、入)

void Graph::DeleteVertex(char v)
{
	int p = GetVertexIndex(v);//找点下标
	if (p == -1)return;

	int i = 0,j = 0;
	int delEdge = 0;//删除边的个数
	for (i = 0; i < m_NumVertex; i++)//计算与该点相连的边的个数
	{
		if (m_Edge[p][i] = 1)
			delEdge++;
	}
	for (i = p; i < m_NumVertex-1; i++)
	{
		m_VertexArr[i] = m_VertexArr[i + 1];//删顶点(把数组中后面的点往前移)
	}
	for (i = p; i < m_NumVertex-1; i++)
	{
		for (j = 0; j < m_NumVertex; j++)
		{
			m_Edge[j][i] = m_Edge[j][i + 1];//删列
		}
	}
	for (i = p; i < m_NumVertex - 1; i++)
	{
		for (j = 0; j < m_NumVertex - 1; j++)
		{
			m_Edge[i][j] = m_Edge[i + 1][j];//删行
		}
	}
	m_NumEdge -= delEdge;//更新边数
	m_NumVertex--;//更新点数
}

方法2:替换法

用最后一个顶点替换要删除的顶点,边用最后一行替换要删的,这样数组大小直接--就可删。

void Graph::DeleteVertex(char v)
{
	int p = GetVertexIndex(v);//找下标
	if (p == -1)return;

	int i = 0, j = 0;
	int delEdge = 0;//删除的边数
	for (i = 0; i < m_NumVertex; i++)//求相连的边数
	{
		if (m_Edge[p][i] = 1)
			delEdge++;
	}
	m_VertexArr[p] = m_VertexArr[m_NumVertex - 1];//要删的点替换成数组中最后一个点
	for (i = 0; i < m_NumVertex; i++)
	{
		m_Edge[i][p] = m_Edge[i][m_NumVertex - 1];//要删的边替换成数组中最后列边
	}
	for (i = 0; i < m_NumVertex - 1; i++)//注意这里点数-1
	{
		m_Edge[p][i] = m_Edge[m_NumVertex - 1][i];//要删的边替换成数组中最后行边
	}
	
	m_NumEdge -= delEdge;//更新边
	m_NumVertex--;//更新点
}

输出

void Graph::PrintGraph()
{
	int i, j;
	cout << "  ";
	for (i = 0; i < m_NumVertex; i++)
	{
		cout << m_VertexArr[i] << " ";//A B C D
	}
	cout << endl;
	for (i = 0; i < m_NumVertex; i++)
	{	
		cout << m_VertexArr[i] << " ";//竖行的ABCD
		for (j = 0; j < m_NumVertex; j++)
		{
			cout << m_Edge[i][j] << " ";//输出边
		}
		cout << endl;
	}
}

测试

int main()
{
	Graph g;
	cout << "插入ABCD顶点,在AB、AD、BC、BD、CD间插入边\n";
	g.InsertVertex('A');
	g.InsertVertex('B');
	g.InsertVertex('C');
	g.InsertVertex('D');
	g.InsertEdge('A', 'B');
	g.InsertEdge('A', 'D');
	g.InsertEdge('B', 'C');
	g.InsertEdge('B', 'D');
	g.InsertEdge('C', 'D');
	g.PrintGraph();
	cout << "删除AD间的边\n";
	g.DeleteEdge('A', 'D');
	g.PrintGraph();
	cout << "删除点B\n";
	g.DeleteVertex('B');
	g.PrintGraph();
}

        

        网的邻接矩阵中无边的为正无穷符号,可以用INT_MAX表示,其他的边数组的值为权值

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

曦樂~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值