转载看到的一个小笑话儿:
男:我是程序员。
女:哦,程先生,你好。
男:客气了,叫我序员就好~
数据结构中,图算是很复杂的东东了吧!对于图的存储结构,主要有五种:邻接矩阵、邻接表、十字链表、邻接多重表和边集数组。
邻接矩阵是用两个数组来存储,一个数组存储顶点的值,另一个二维数组存储顶点之间的连接信息;这种结构虽适用于无向图和有向图,但对于稀疏图,会造成存储空间的浪费,因此引入了邻接表。
邻接表分为顶点表和边表,顶点表存储顶点的值以及该顶点指向边表的第一个结点,即此顶点的第一个邻接点;边表存储某顶点的邻接点在顶点表中的下标,以及存储边表中指向下一个结点的指针。邻接表可以很方便的计算出无向图中某一顶点的出度和入度,但对于有向图,如果边表是以顶点为弧尾来存储的,那么查找某顶点的出度是很方便的,但计算某顶点的入度则只能遍历了,因此,提出了十字链表。
对于无向图,如果我们删除某条边,显然操作起来并不方便,因此引入了邻接多重表 。如果我们更强调对边的操作,那么边集数组会是很好的选择,它一共使用了两个数组来存储,第一个数组存储顶点值,第二个数组中的每个元素共包含某条边的起点、终点和边上的权值,但这种存储结构弱化了对顶点的操作。
有了图的存储结构,接下来就得考虑图的遍历问题 了。图的遍历主要有两种方法:深度优先遍历(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;
}