图的实现是一件很麻烦的事情,很多同学可能在学数据结构时只是理解了图的基本操作和遍历原理,但并没有动手实践过。在此,我说说我的实现过程。

首先,在草稿纸上画一个图表,这里是有向图,无向图也一样,如下:

我用的是vector+vector容器作为存储结构,如下:vector+vector)
                                                 |0|——|1|——|3|
                                                 |1|——|2|——|3|
                                                 |2|——|3|
                                                 |3|

第二步,用自然语言建立这个图,注意数据结构的书一般没有说明图是怎么建立的,在此我简述一下:

1)、加入4个顶点——G.InsertVextex(V);

2)、在两个顶点之间增加有向弧——G.AddEdge(x, y)。

这样图就建立了。

我写了两个Graph的构造函数,也可以直接用一个数组实现1)的操作如下:

vector<VNode> v(4);

Graph G(v);

第三步,广度优先遍历和深度优先遍历。遍历的目的是为了对每个顶点进行一些处理,能够遍历这个图是其他操作的基础。甚至可以用遍历的方法建立这个图,就像我之前用先序遍历建立二叉树一个道理。

这三步完成,图的实现就基本解决了。至于最小生成树、关键路径等问题,以后再说。

/*************************
Date : 2013-9-14
Author : DVD0423
Function: 有向图 存储结构如下:(vector+vector)
|0|——*——*——*
|1|——*
|2|——*——*
|3|——*——*——*——*——*
|4|——*——*——*
|5|
|6|——*——*
|7|——*
***************************/
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef int DataType;
const DataType INIT_DATA = -1;
const int NO_NODE = -1;
const int NO_EDGE = -2; class VNode{
public:
//data member
bool visited; //访问标志
DataType data; //顶点内的数据
vector<int> e; //邻接的边
//member function
VNode(DataType val = INIT_DATA, bool flag = false):data(val), visited(flag){}
void Visit()
{
cout<<data<<"\t";
}
bool operator== (VNode &y){
if(data == y.data && e == y.e)
return true;
else
return false;
}
};
class Graph{
public:
//data member
int vexnum; //图中顶点数
int edgenum; //图中边数
vector<VNode> V; //图的存储结构
//member function
Graph()
{
vexnum = 0;
edgenum = 0;
}
Graph(vector<VNode> &v);
int GetVexNum();
int GetEdgeNum();
//节点操作
void InsertVertex(VNode &x);
bool DeleteVertex(int x);
//边的操作
//bool IfEdge(int x, int y); //判断是否有(x, y)的边
bool AddEdge(int x, int y);
bool RemoveEdge(int x, int y);
//邻边操作
void PrintNeighbors(int x); //
VNode &Neighbor(VNode &x, int n); //x的第n个邻接节点,默认n为第一个
//广度遍历和深度遍历
void BreadthFirstSearch();
void BFS(VNode &x); //队列实现
void DepthFirstSearch();
void DFS(VNode &x); //递归函数
~Graph(){};
};
Graph::Graph(vector<VNode> &v)
{
V.assign(v.begin(), v.end());
vexnum = V.size();
edgenum = GetEdgeNum();
} int Graph::GetVexNum()
{
vexnum = V.size();
return vexnum;
} int Graph::GetEdgeNum()
{
edgenum = 0;
for(vector<VNode>::iterator iter = V.begin(); iter != V.end(); ++iter)
{
edgenum += iter->e.size();
}
return edgenum;
} void Graph::InsertVertex(VNode &x)
{
V.push_back(x);
vexnum++;
}
//删除x节点
bool Graph::DeleteVertex(int x)
{
if(x >= V.size() || x < 0)
{
cout<<"没有相应节点"<<endl;
return false;
}
vector<VNode>::iterator iter = V.begin()+x;
V.erase(iter);
vexnum--;
return true;
} bool Graph::AddEdge(int x, int y)
{
if((x >= V.size() || x < 0) || (y >= V.size() || y < 0))
{
cout<<"没有相应节点"<<endl;
return false;
}
int size = V[x].e.size();
for(vector<int>::iterator iter = V[x].e.begin(); iter != V[x].e.end(); ++iter)
{
if(V[*iter] == V[y]) //已经有(x, y)
{
cout<<"已经有弧(x, y)"<<endl;
return false;
}
}
V[x].e.push_back(y); //没有,则把y加入x的邻边队列中
edgenum++;
return true;
}
bool Graph::RemoveEdge(int x, int y)
{
if((x >= V.size() || x < 0) || (y >= V.size() || y < 0))
{
cout<<"没有相应节点"<<endl;
return false;
}
for(vector<int>::iterator iter = V[x].e.begin(); iter != V[x].e.end(); ++iter)
{
if(V[*iter] == V[y])
{
V[x].e.erase(iter);
edgenum--;
return true;
}
}
cout<<"没有弧(x, y)"<<endl;
return false;
} //邻边操作
void Graph::PrintNeighbors(int x)
{
cout<<"列出节点"<<x<<"的所有邻接节点"<<endl;
for(vector<int>::iterator iter = V[x].e.begin(); iter != V[x].e.end(); ++iter)
{
cout<<*iter<<"\t";
}
cout<<endl;
} VNode &Graph::Neighbor(VNode &x, int n = 1)
{ if(n > x.e.size() || n <= 0)
{
cout<<"没有相应边"<<endl;
exit(0);
}
return V[(x.e[n-1])];
}
/******
遍历
**********/
void Graph::BreadthFirstSearch()
{
for(int i = 0; i != vexnum; ++i)
{
if(!V[i].visited)
BFS(V[i]);
}
for(vector<VNode>::iterator k = V.begin(); k != V.end(); ++k)
k->visited = false; }
void Graph::BFS(VNode &x)
{
queue<VNode> q;
q.push(x);
while(!q.empty())
{
VNode &_x = q.front();
if(!_x.visited)
{
_x.Visit();
_x.visited = true;
int size = _x.e.size(); for(int i = 0; i < size; ++i)
{
VNode &w = V[_x.e[i]];
if(!w.visited)
{
w.Visit();
w.visited = true;
q.push(w);
}
}
}
q.pop();
}
} void Graph::DepthFirstSearch()
{
for(int i = 0; i != vexnum; ++i)
{
if(!V[i].visited)
DFS(V[i]);
}
for(vector<VNode>::iterator k = V.begin(); k != V.end(); ++k)//改变访问标志,以便下次访问
k->visited = false;
}
void Graph::DFS(VNode &x)
{ x.Visit();
x.visited = true;
int size = x.e.size();
for(int i = 0; i < size; ++i)
{
VNode &w = V[x.e[i]];
if(!w.visited)
DFS(w);
}
}

下面是main函数

int main()
{
Graph G;
vector<VNode> v(4);
for(int i = 0; i != 4; ++i)
{
v[i].data = i; //节点信息
G.InsertVertex(v[i]);
}
//Graph G(v);
G.AddEdge(0, 1);
G.AddEdge(0, 3);
G.AddEdge(1, 2);
G.AddEdge(2, 3);
G.AddEdge(1, 3); G.BreadthFirstSearch();
return 0;
}

C++数据结构之图的更多相关文章

  1. python数据结构之图的实现

    python数据结构之图的实现,官方有一篇文章介绍,http://www.python.org/doc/essays/graphs.html 下面简要的介绍下: 比如有这么一张图: A -> B ...

  2. hdu 1233:还是畅通工程(数据结构,图,最小生成树,普里姆(Prim)算法)

    还是畅通工程 Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Total Submis ...

  3. 利用python+graphviz绘制数据结构关系图和指定目录下头文件包含关系图

    作为一名linux系统下的C语言开发,日常工作中经常遇到两个问题: 一是分析代码过程中,各种数据结构互相关联,只通过代码很难理清系统中所有结构体的整体架构,影响代码消化的效率; 二是多层头文件嵌套包含 ...

  4. python数据结构之图的实现方法

    python数据结构之图的实现方法 本文实例讲述了python数据结构之图的实现方法.分享给大家供大家参考.具体如下: 下面简要的介绍下: 比如有这么一张图:     A -> B     A ...

  5. python数据结构之图深度优先和广度优先实例详解

    本文实例讲述了python数据结构之图深度优先和广度优先用法.分享给大家供大家参考.具体如下: 首先有一个概念:回溯 回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到 ...

  6. 数据结构之图 Part2 - 1

    邻接矩阵 网上很少有C# 写图的数据结构的例子,实际的项目中也从来没用过Array 这坨东西,随手写个,勿喷. namespace LH.GraphConsole { public struct Gr ...

  7. 数据结构之图 Part1

    Part 1 预计使用7天的时间来过掉图相关的数据结构.第一天主要是一天图的基本概念,熟练掌握定义是一切交流和沟通的基础. 1定义 1.1图 有穷非空顶点,外加边. G(V,E) Graph Vert ...

  8. 数据结构之--图(Graphics)

    1.1:图的定义和术语   图是一种比线性表和树更为复杂的数据结构.在线性表中,数据元素之间仅有线性关系,每个元素仅有一个直接前驱和一个直接后继:在树形结构中,数据元素之间有着明显的层次关系,并且每一 ...

  9. 【js数据结构】图的深度优先搜索与广度优先搜索

    图类的构建 function Graph(v) {this.vertices = v;this.edges = 0;this.adj = []; for (var i = 0; i < this ...

随机推荐

  1. C#复习二(Twenty First Day)

    呵呵,又来到了今天的总结.这次主要复习了一下字符串的一些处理.今天就来总结一下. 理论: —String 字符串,字符串可以看成字符数组,不可变特性(通过for循环,修改string中的元素,失败!) ...

  2. C#编写的windows服务安装后启动提示“服务启动后又停止了”

    使用C#编写的windows服务安装到服务器上行后进行启动时,总是提示“服务启动后又停止了”. 检查了服务逻辑是没问题,安装在开发本地也是正常,网上查了资料说是可能是服务没有注册,我检查了服务是正常注 ...

  3. Unity Editor下对资源进行操作时调用AssetModificationProcessor

    public class Test : UnityEditor.AssetModificationProcessor { private static void OnWillCreateAsset(s ...

  4. Java 重写(Override)与重载(Overload)

    1.重写(Override) 重写是子类对父类的允许访问的方法的实现过程进行重新编写!返回值和形参都不能改变.即外壳不变,核心重写! 参数列表和返回值类型必须与被重写方法相同. 访问权限必须低于父类中 ...

  5. Python 爬取CSDN博客频道

    初次接触python,写的很简单,开发工具PyCharm,python 3.4很方便 python 部分模块安装时需要其他的附属模块之类的,可以先 pip install wheel 然后可以直接下载 ...

  6. git版本控制的笔记

    一.配置你的身份,提交代码时git就可以知道是谁提交的了 git config --global user.name "Tony" git config --global user ...

  7. Linux串口编程详解(转)

    串口本身,标准和硬件 † 串口是计算机上的串行通讯的物理接口.计算机历史上,串口曾经被广泛用于连接计算机和终端设备和各种外部设备.虽然以太网接口和USB接口也是以一个串行流进行数据传送的,但是串口连接 ...

  8. 嵌入式C开发人员的最好的0x10道笔试题

    嵌入式C开发人员的最好的0x10道笔试题 2006-11-22 15:53 约定: 1) 下面的测试题中,认为所有必须的头文件都已经正确的包含了 2)数据类型 char 一个字节 1 byte int ...

  9. MVC-07 案例2

    二.电子商务网站 掌握该网站的开发流程和设计思路,并为数据模型中商品.商品分类,这两个类编写代码. 1.需求分析 2.数据模型规划 (1)商品类别 (2)商品信息 (3)会员信息 (4)购物车项目 ( ...

  10. wordpress 首页模板变量对应表

    最近开始学习wp,这里做一些笔记. 首页模板,第一行为前台显示的html代码.第二行为 wp-content/themes/模板目录 下 head.php文件中. 其中我将变量名 html用绿色标记 ...