三、图的建立及遍历

转载看到的一个小笑话儿:

男:我是程序员。 
女:哦,程先生,你好。 
男:客气了,叫我序员就好~


数据结构中,图算是很复杂的东东了吧!对于图的存储结构,主要有五种:邻接矩阵、邻接表、十字链表、邻接多重表和边集数组。

邻接矩阵是用两个数组来存储,一个数组存储顶点的值,另一个二维数组存储顶点之间的连接信息;这种结构虽适用于无向图和有向图,但对于稀疏图,会造成存储空间的浪费,因此引入了邻接表。

邻接表分为顶点表和边表,顶点表存储顶点的值以及该顶点指向边表的第一个结点,即此顶点的第一个邻接点;边表存储某顶点的邻接点在顶点表中的下标,以及存储边表中指向下一个结点的指针。邻接表可以很方便的计算出无向图中某一顶点的出度和入度,但对于有向图,如果边表是以顶点为弧尾来存储的,那么查找某顶点的出度是很方便的,但计算某顶点的入度则只能遍历了,因此,提出了十字链表。

对于无向图,如果我们删除某条边,显然操作起来并不方便,因此引入了邻接多重表 。如果我们更强调对边的操作,那么边集数组会是很好的选择,它一共使用了两个数组来存储,第一个数组存储顶点值,第二个数组中的每个元素共包含某条边的起点、终点和边上的权值,但这种存储结构弱化了对顶点的操作。


有了图的存储结构,接下来就得考虑图的遍历问题 了。图的遍历主要有两种方法:深度优先遍历(DFS, Depth First Search)和广度优先遍历(BFS, Breadth First Search)。深度优先遍历实质上是以任意一个顶点开始,以类似于二叉树的前序遍历方式遍历整个图;广度优先遍历类似于二叉树中的层序遍历。


以下是我根据书中讲解的内容,用C++实现的邻接矩阵、邻接表和图的两种遍历方法:

#include <iostream>
#include <queue>
using namespace std;
const int maxSize = 20;
#define Infinity 65535;

//邻接矩阵
struct adjacencyMatrixGraph
{
	int vertex[maxSize];
	int vertexVector[maxSize][maxSize];
	int vertexes,edges;//顶点数和边数
};
//邻接表
struct edgeList
{
	int subscript;
	edgeList *next;
};//边表
struct vertexList
{
	int data;
	edgeList *firstEdge;
};//顶点
struct adjacencyListGraph
{
	vertexList adjacencyList[maxSize];
	int vertexes,edges;//顶点数和边数
};

//以邻接矩阵存储结构创建一个无向图
void createGraph_AdjacencyMatrix(adjacencyMatrixGraph *aMG)
{
	cout<<"请输入顶点数和边数:"<<endl;
	cin>>aMG->vertexes>>aMG->edges;
	cout<<"请依次输入各顶点的值,以空格分开:"<<endl;
	for (int i = 0; i < aMG->vertexes; i++)
	{
		cin>>aMG->vertex[i];
	}
	//邻接矩阵初始化
	for (int i=0; i< aMG->vertexes; i++)
	{
		for (int j=0;j<aMG->vertexes; j++)
		{
			aMG->vertexVector[i][j] = Infinity;
		}
	}
	//按照每条边的形式输入邻接矩阵
	for (int k=0;k<aMG->edges;k++)
	{
		int i,j,w;
		cout<<"请输入边(Vi,Vj)的下标i、j以及权值w:"<<endl;
		cin>>i>>j>>w;
		aMG->vertexVector[i][j] = w;
		aMG->vertexVector[j][i] = w;
	}
}

//以邻接表存储结构创建一个无向图
void createGraph_AdjacencyList(adjacencyListGraph *aLG)
{
	cout<<"请输入顶点数和边数:"<<endl;
	cin>>aLG->vertexes>>aLG->edges;
	cout<<"请依次输入各顶点的值,以空格分开:"<<endl;
	for (int i = 0; i < aLG->vertexes; i++)
	{
		cin>>aLG->adjacencyList[i].data;
		aLG->adjacencyList[i].firstEdge = nullptr;
	}
	//按照每条边的形式输入,建立边表
	for (int k=0;k<aLG->edges;k++)
	{
		int i,j;
		cout<<"请输入边(Vi,Vj)上的顶点序号:"<<endl;
		cin>>i>>j;

		edgeList *e = new edgeList;
		e->subscript = j;
		e->next = aLG->adjacencyList[i].firstEdge;
		aLG->adjacencyList[i].firstEdge = e;

		edgeList *f = new edgeList;
		f->subscript = i;
		f->next = aLG->adjacencyList[j].firstEdge;
		aLG->adjacencyList[j].firstEdge = f->next;
	}
}

//邻接矩阵的深度优先遍历
bool visited[maxSize];//标志位,为true表明该顶点已遍历过
void DFS_aMG(adjacencyMatrixGraph *aMG, int i)
{
	visited[i] = true;
	cout<<aMG->vertex[i]<<" ";
	for (int j=0;j<aMG->vertexes;j++)
	{
		if (aMG->vertexVector[i][j] == 1 && !visited[j])
		{
			DFS_aMG(aMG,j);
		}
	}
}
void DFSTraverse_aMG(adjacencyMatrixGraph *aMG)
{
	for (int i=0;i<aMG->vertexes;i++)
	{
		visited[i] = false;
	}
	for (int i=0;i<aMG->vertexes;i++)
	{
		if (!visited[i])
		{
			DFS_aMG(aMG,i);
		}
	}
}
//邻接表的深度优先遍历
void DFS_aLG(adjacencyListGraph *aLG, int i)
{
	visited[i]=true;
	cout<<aLG->adjacencyList[i].data<<" ";
	edgeList *temp = aLG->adjacencyList[i].firstEdge;
	while(temp != nullptr)
	{
		if (!visited[temp->subscript])
			DFS_aLG(aLG,temp->subscript);
		temp = temp->next;
	}
}
void DFSTraverse_aLG(adjacencyListGraph *aLG)
{
	for (int i=0;i<aLG->vertexes;i++)
	{
		visited[i] = false;
	}
	for (int i=0;i<aLG->vertexes;i++)
	{
		if (!visited[i])
		{
			DFS_aLG(aLG,i);
		}
	}
}

//邻接矩阵的广度优先遍历
void BFSTraverse_aMG(adjacencyMatrixGraph *aMG)
{
	int i,j;
	queue<int> Q;
	for (i=0;i<aMG->vertexes;i++)
	{
		visited[i]=false;
	}
	for (i=0;i<aMG->vertexes;i++)
	{
		if (!visited[i])
		{
			visited[i] = true;
			cout<<aMG->vertex[i]<<" ";
			Q.push(i);
			while(!Q.empty())
			{
				i=Q.front();
				Q.pop();
				for (j=0;j<aMG->vertexes;j++)
				{
					if (aMG->vertexVector[i][j] == 1 && !visited[j])
					{
						visited[j] = true;
						cout<<aMG->vertex[j]<<" ";
						Q.push(j);
					}
				}
			}
		}
	}
}
//邻接表的广度优先遍历
void BFSTraverse_aLG(adjacencyListGraph *aLG)
{
	int i,j;
	edgeList *p;
	queue<int> Q;
	for (i=0;i<aLG->vertexes;i++)
	{
		visited[i]=false;
	}
	for (i=0;i<aLG->vertexes;i++)
	{
		if (!visited[i])
		{
			visited[i]=true;
			cout<<aLG->adjacencyList[i].data<<" ";
			Q.push(i);
			while(!Q.empty())
			{
				j = Q.front();
				Q.pop();
				p= aLG->adjacencyList[j].firstEdge;
				while(p != nullptr)
				{
					if (!visited[p->subscript])
					{
						visited[p->subscript] = true;
						cout<<aLG->adjacencyList[p->subscript].data<<" ";
						Q.push(p->subscript);
					}
					p = p->next;
				}
			}
		}
	}
}

int main()
{
 	adjacencyMatrixGraph myAMG;
 	adjacencyListGraph myLMG;
 	createGraph_AdjacencyMatrix(&myAMG);
 	cout<<"深度优先遍历的结果为:"<<endl;
 	DFSTraverse_aMG(&myAMG);
 	cout<<endl;
 	cout<<"广度优先遍历的结果为:"<<endl;
 	BFSTraverse_aMG(&myAMG);
 	cout<<endl;

	createGraph_AdjacencyList(&myLMG);
	cout<<"深度优先遍历的结果为:"<<endl;
	DFSTraverse_aLG(&myLMG);
	cout<<endl;
	cout<<"广度优先遍历的结果为:"<<endl;
	BFSTraverse_aLG(&myLMG);
	cout<<endl;

	return 0;
}
    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/kukutengteng/article/details/22068631
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞