图的表示方法主要有邻接矩阵和邻接表。其中邻接表最为常用,因此这里便以邻接表为例介绍一下图的创建及遍历方法。

创建图用到的结构有两种:顶点及弧

struct ArcNode
{
int vertexIndex; //该弧指向的顶点位置
struct ArcNode* next; //指向下一个弧
InfoType info; //该弧的相关信息,如权重等
}; struct Vertex
{
VertexType data; //顶点信息
ArcNode* firstArc; //指向第一条依附该节点弧的指针
ColorType color; //访问情况
};

  其中ColorType是一个枚举,遍历的时候才会用到。图的创建比较简单,直接看代码很容易理解,这里不再详细说了。 图的深度和广度遍历直接看算法导论中的两张图就明白了 :

//结点颜色代表遍历情况
enum ColorType
{
WHITE, //未访问
GRAY, //正在访问,邻接点还没访问完
BLACK //访问完毕
};

 
代码:
 #include <queue>
#include <stack>
#include <iostream>
using namespace std; enum GraphType
{
UNDIR_UNWEIGHT_GRAPH, //无向无权图
UNDIR_WEIGHT_GRAPH, //无向带权图
DIR_UNWEIGHT_GRAPH, //有向无权图
DIR_WEIGHT_GRAPH //有向带权图
}; //结点颜色代表遍历情况
enum ColorType
{
WHITE, //未访问
GRAY, //正在访问,邻接点还没访问完
BLACK //访问完毕
}; template<typename VertexType,typename InfoType>
class Graph
{
public:
Graph(int vertexNum, GraphType type) :m_vertexNum(vertexNum), m_type(type), m_arcNum()
{
for (int i = ; i < MAX_VERTEX_NUM; ++i)
{
m_vertices[i].firstArc = nullptr;
}
} void Create()
{
switch (m_type)
{
case UNDIR_UNWEIGHT_GRAPH:
CreateUndirUnweightGraph();
break;
case UNDIR_WEIGHT_GRAPH:
CreateUndirWeightGraph();
break;
case DIR_UNWEIGHT_GRAPH:
CreateDirUnweightGraph();
break;
case DIR_WEIGHT_GRAPH:
CreateDirWeightGraph();
break;
default:
break;
}
} //输出图的信息
void Display()
{
for (int i = ; i < m_vertexNum; ++i)
{
cout << "第" << i + << "个结点为" << m_vertices[i].data << " 邻接表为:";
ArcNode* node = m_vertices[i].firstArc;
while (node)
{
cout << "->" << m_vertices[node->vertexIndex].data << "(" << node->info << ")";
node = node->next;
}
cout << endl;
}
} void BFS()
{
for (int i = ; i < m_vertexNum; ++i)
{
m_vertices[i].color = WHITE;
}
cout << "图的广度优先遍历为:";
BFS(&m_vertices[]);
cout << endl;
} void DFS()
{
for (int i = ; i < m_vertexNum; ++i)
{
m_vertices[i].color = WHITE;
}
cout << "图的深度优先遍历为:";
DFS(&m_vertices[]);
cout << endl;
}
private:
struct ArcNode
{
int vertexIndex; //该弧指向的顶点位置
struct ArcNode* next; //指向下一个弧
InfoType info; //该弧的相关信息,如权重等
}; struct Vertex
{
VertexType data; //顶点信息
ArcNode* firstArc; //指向第一条依附该节点弧的指针
ColorType color; //访问情况
}; //最大顶点数
static const int MAX_VERTEX_NUM = ;
Vertex m_vertices[MAX_VERTEX_NUM]; //顶点列表
int m_vertexNum; //当前顶点数量
int m_arcNum; //当前弧数量
GraphType m_type; //图类型:有向无权图、有向带权图、无向无权图、无向无权图
private:
//初始化顶点列表
void InitVertices()
{
cout << "请输入每个顶点的关键字" << endl;
VertexType data;
for (int i = ; i < m_vertexNum; ++i)
{
cin >> data;
m_vertices[i].data = data;
}
}
//插入一个表结点
void Insert(int headVertex, int tailVertex, InfoType info)
{
//构造一个邻接表结点,即创建一条弧
ArcNode* newNode = new ArcNode;
newNode->info = info;
newNode->next = nullptr;
newNode->vertexIndex = tailVertex; //找到邻接表的最后一个节点
ArcNode* lastNode = m_vertices[headVertex].firstArc;
if (lastNode == nullptr)
m_vertices[headVertex].firstArc = newNode;
else
{
while (lastNode->next)
{
lastNode = lastNode->next;
}
lastNode->next = newNode;
}
++m_arcNum;
} //创建无向无权图
void CreateUndirUnweightGraph()
{
InitVertices();
cout << "请分别输入每条边的起始结点:" << endl;
int head, tail;
while (cin >> head >> tail)
{
//无向图head->tail tail->head插入两次
Insert(head, tail, );
Insert(tail, head, );
}
}
//创建无向有权图
void CreateUndirWeightGraph()
{
InitVertices();
cout << "请分别输入每条边的起始结点和权值:" << endl;
int head, tail;
InfoType weight;
while (cin >> head >> tail >> weight)
{
Insert(head, tail, weight);
Insert(tail, head, weight);
}
}
//创建有向无权图
void CreateDirUnweightGraph()
{
InitVertices();
cout << "请分别输入每条边的起始结点值:" << endl;
int head, tail;
while (cin >> head >> tail)
{
Insert(head, tail,);
}
}
//创建有向带权图
void CreateDirWeightGraph()
{
InitVertices();
cout << "请分别输入每条边的起始结点和权值:" << endl;
int head, tail;
InfoType weight;
while (cin >> head >> tail >> weight)
{
Insert(head, tail, weight);
}
} void BFS(Vertex* vertex)
{
vertex->color = GRAY;
queue<Vertex*> vertices;
vertices.push(vertex);
while (!vertices.empty())
{
Vertex* curVertex = vertices.front();
vertices.pop();
cout << curVertex->data << "->";
ArcNode* node = curVertex->firstArc;
while (node)
{
Vertex* tmpVertex = &m_vertices[node->vertexIndex];
if (tmpVertex->color == WHITE)
{
tmpVertex->color = GRAY;
vertices.push(tmpVertex);
}
node = node->next;
}
curVertex->color = BLACK;
}
} void DFS(Vertex* vertex)
{
vertex->color = GRAY;
stack<Vertex*> vertices;
vertices.push(vertex);
while (!vertices.empty())
{
Vertex* curVertex = vertices.top();
vertices.pop();
cout << curVertex->data << "->";
ArcNode* node = curVertex->firstArc;
while (node)
{
Vertex* tmp = &m_vertices[node->vertexIndex];
if (tmp->color == WHITE)
{
tmp->color = GRAY;
vertices.push(tmp);
}
node = node->next;
}
curVertex->color = BLACK;
}
}
}; int main()
{
int vertexNum;
cout << "请输入要创建的图的结点数:";
cin >> vertexNum;
Graph<char, int> g(vertexNum,GraphType::UNDIR_UNWEIGHT_GRAPH);
g.Create();
g.Display();
g.BFS();
g.DFS();
}
 
运行结果:(创建的树为算法导论BFS说明图片中的树)

 
 

图的创建和遍历(BFS/DFS)的更多相关文章

  1. 【算法导论】图的深度优先搜索遍历(DFS)

    关于图的存储在上一篇文章中已经讲述,在这里不在赘述.下面我们介绍图的深度优先搜索遍历(DFS). 深度优先搜索遍历实在访问了顶点vi后,访问vi的一个邻接点vj:访问vj之后,又访问vj的一个邻接点, ...

  2. JS实现图的创建和遍历

    图分为无向图和有向图 图的存储结构有邻接矩阵.邻接表.十字链表.邻接多重表这四种,最常用的是前两种 本篇主要是利用邻接矩阵实现无向图的创建和遍历(深度优先.广度优先),深度优先其实就是二叉树里的前序遍 ...

  3. 图的两种遍历:DFS&BFS

    DFS和BFS在图中的应用: 图连通性判定:路径的存在性:图中是否存在环:求图的最小生成树:求图的关键路径:求图的拓扑排序. DFS:简单的说,先一直往深处走,直到不能再深了,再从另一条路开始往深处走 ...

  4. 模板 图的遍历 bfs+dfs 图的最短路径 Floyed+Dijkstra

    广搜 bfs //bfs #include<iostream> #include<cstdio> using namespace std; ],top=,end=; ][]; ...

  5. 图的广度优先/层次 遍历(BFS) c++ 队列实现

    在之前的博文中,介绍了图的深度优先遍历,并分别进行了递归和非递归实现.BFS 无法递归实现,最广泛的实现是利用队列(queue).这与DFS的栈实现是极其相似的,甚至代码几乎都很少需要改动.从给定的起 ...

  6. 算法导论—无向图的遍历(BFS+DFS,MATLAB)

    华电北风吹 天津大学认知计算与应用重点实验室 最后改动日期:2015/8/22 无向图的存储方式有邻接矩阵,邻接链表,稀疏矩阵等. 无向图主要包括双方面内容,图的遍历和寻找联通分量. 一.无向图的遍历 ...

  7. 数据结构(三十二)图的遍历(DFS、BFS)

    图的遍历和树的遍历类似.图的遍历是指从图中的某个顶点出发,对图中的所有顶点访问且仅访问一次的过程.通常有两种遍历次序方案:深度优先遍历和广度优先遍历. 一.深度优先遍历 深度优先遍历(Depth_Fi ...

  8. 图的深度优先遍历(DFS)和广度优先遍历(BFS)

    body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...

  9. 数据结构作业——图的存储及遍历(邻接矩阵、邻接表+DFS递归、非递归+BFS)

    邻接矩阵存图 /* * @Author: WZY * @School: HPU * @Date: 2018-11-02 18:35:27 * @Last Modified by: WZY * @Las ...

随机推荐

  1. KMP算法(具体求串的next[n])

     怎么求串的模式值next[n]   )next[0]= -1  意义:不论什么串的第一个字符的模式值规定为-1. )next[j]= -1   意义:模式串T中下标为j的字符,假设与首字符 同样,且 ...

  2. thinkphp 3.2.3 入门示例2(URL传参数的几种方式)

    原文:thinkphp中URL传参数的几种方式 在thinkphp中,url传参合asp.net中原理类似,下面就单个参数和多个参数传递方式进行一个简单讲解 1.传单个参数 单个参数这种比较简单,例如 ...

  3. 使用HashMap须要注意的事儿:不要暴露Map.entry给外部不可信代码Map.entrySet()

    Map/HashMap是java中一种非经常常使用的数据结构,一般我们在应用中做的事情就是调用put向容器写入数据或者是get从容器读取数据. Map.entrySet()这种方法返回了键值对的集合, ...

  4. 在C#中子线程如何操作主窗口线程上的控件

    在C#中子线程怎样操作主线程中窗口上控件 在C#中,直接在子线程中对窗口上的控件操作是会出现异常,这是因为子线程和运行窗口的线程是不同的空间,因此想要在子线程来操作窗口上的控件.是不可能简单的通过控件 ...

  5. SPOJ PGCD(莫比乌斯反演)

    传送门:Primes in GCD Table 题意:给定两个数和,其中,,求为质数的有多少对?其中和的范围是. 分析:这题不能枚举质数来进行莫比乌斯反演,得预处理出∑υ(n/p)(n%p==0). ...

  6. Android设备管理器漏洞2--禁止用户取消激活设备管理器

    2013年6月,俄罗斯安全厂商卡巴斯基发现了史上最强手机木马-Obad.A.该木马利用了一个未知的Android设备管理器漏洞(ANDROID-9067882),已激活设备管理器权限的手机木马利用该漏 ...

  7. hdu5119(dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5119 分析:dp[i][j]表示由前i个数组成异或和为j的方法数,则dp[i][j]=d[i-1][j ...

  8. HTML5之画布的拖拽/拖放

    <!DOCTYPE HTML> <html> <head> <script type="text/javascript"> func ...

  9. Android 网络通信框架Volley基本介绍

    Volley主页 https://android.googlesource.com/platform/frameworks/volley http://www.youtube.com/watch?v= ...

  10. 安装IntelliJ IDEA JetGroovy(转)

    JetGroovy是一个免费而且开源的专用于支持Groovy和Grails的IntelliJ IDEA插件.这个插件是由JetBrains公司自己开发的,对于Groovy语言和Web框架都提供了无以伦 ...