您的位置:首页 > 理论基础 > 数据结构算法

详解数据结构——图之邻接矩阵表示法

2016-10-29 22:54 309 查看
一、图的建立

图是表达“多对多”的关系的一种数据结构。

它由非空的有限顶点集合和有限边集合组成。

1. 顶点集合常常由数组表示。

数组下标表示顶点位置。

数组内容包含顶点数据,并且要添加判定是否被访问过的标志标量,为其余操作提供参数。

其数据类型定义如下:

struct Vertex {
T data;
bool isVisited;
}

2. 边集合的存储常用邻接矩阵或者邻接表。

边数值(权值)表示顶点之间有某种关系,0表示两个顶点之间没有边,也即没有关系。

邻接矩阵是一个二维数组,matrix[顶点数][顶点数]。也可定义为一个省一半空间的一维数组 n(n+1)/2,不利于理解,不作说明。

最简单的图用来呈现顶点之间的关系。顶点类型可以只包含一个用来判断是否被访问过的标志变量。用bool或者int数组表示顶点。

<pre name="code" class="cpp">//graph.h#ifndef GRAGH_H

#define GRAGH_H

class Graph {

public:

Graph(const int &capacity);

~Graph();

void insertEdge(const int &indexA, const int &indexB, const int &weight = 1);

//成员变量只需要三个。

private:

int capacity; //图的顶点个数。

bool *pVertex; //存储图的顶点。

int *pMatrix; //存储图的边。

}

#endif


实现文件:

//graph.cpp
#include "graph.h"

/*
通过初始化列表建立一张图。
并对pVertex、pMatrix进行值初始化。
pVertex的每个元素值初始化为false,pMatrix的每个元素值初始化为0.
*/
inline
Graph::Graph(const int &capacity):
capacity(capacity),
pVertex(new bool[capacity]()),
pMatrix(new int[capacity * capacity]()) {}

<span style="color:#808000;">inline</span><pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style="color:#800080;">Graph</span><span style="color:#000000;">::~</span><span style="color:#800080;">Graph</span><span style="color:#000000;">()</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">{</span>
delete[] pVertex;

delete[] pMatrix;

}


inline
void Graph::insertEdge(const
int
&indexA,
const
int &indexB,
const
int weight)
{
//插入一条从A点指向B点的边。

pMatrix[indexA * capacity + indexB] = weight;

//无向图需要插入一条从B指向A的边。

pMatrix[indexB * capacity + indexA] = weight;

}



1. pVertex下标表示顶点位置。

2. pVertex值表示顶点是否被访问过,初始化为false。

3. pMatrix值表示顶点之间的关系,初始化为0。

4. 添加边的信息,就形成了一张图。

二、图的遍历

有了图之后,我们就要对它进行一些操作。

首先是遍历:

1. 深度优先搜索Depth First Search,类似于树的先序遍历。

2. 广度优先搜索Breadth First Search,类似于树的层序遍历。

为此,在graph.h头文件中添加四个函数:

//graph.h
public:
<span style="color:#808000;"> void</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">DFS</span><span style="color:#000000;">(</span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span>index<span style="color:#000000;">);</span><pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style="color:#c0c0c0;"> </span><span style="color:#808000;">void</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">BFS</span><span style="color:#000000;"
4000
>(</span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span>index<span style="color:#000000;">);</span>
void resetVertex();

private:
const int& getEdgeWeight(const int &indexA, const int &indexB);



其中的resetVertex是用来在下一个遍历之前,重置所有的顶点为未访问过的状态。

若是用int数组表示,则可传入一个值,用来判定顶点的访问状态,也就不需要resetVertex。

而getEdgeWeight函数是返回从A点到B点的边的权值,代表了两个顶点的关系。

其实现如下:

//graph.cpp
#include <iostream>
#include <queue> //包含头文件,为BFS提供队列容器。

<span style="color:#808000;">inline</span><pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#000000;">&</span><span style="color:#c0c0c0;"> </span><span style="color:#800080;">Graph</span><span style="color:#000000;">::</span><span style="color:#000000;">getEdgeWeight</span><span style="color:#000000;">(</span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span><span style="color:#000000;">indexA</span><span style="color:#000000;">,</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span><span style="color:#000000;">indexB</span><span style="color:#000000;">)</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">{</span>
return pMatrix[indexA * capacity + indexB];

}


//打印出从index开始,进行深度优先的索引次序。
void Graph::DFS(const int &index) {

std::cout << index << " ";

pVertex[index] = true;

for(int i(0); i < capacity; ++i) {

if(getEdgeWeight(index, i) > 0 && !pVertex[i])

DFS(i);

}

}

/打印出从index开始,进行广度优先的索引次序。
void Graph::BFS(const int &index) {
std::queue<int> que;
que.push(index);
pVertex[index] = true;
while(!que.empty()) {
int subcript(que.front());
que.pop();
std::cout << subcript << " ";
for(int i(0); i < capacity; ++i) {
if(getEdgeWeight(subcript, i) > 0 && !pVertex[i]) {
que.push(i);
pVertex[i] = true;
}
}
}
}


//重置顶点为未访问过。
void Graph::resetVertex() {

for(int i(0); i < capacity; ++i)

pVertex[i]= false;

}




三、最短路径Shortest Path

图的重要应用之一,最短路径。

。。。怎么感觉写博客好累啊,写了一个多小时,才写了这么点儿。

后面的最短路径和最小生成树感觉这样写下去得四五个小时。

有空再写完。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息