当前位置: 首页 > wzjs >正文

深圳网站建设软件定制公司每日财经要闻

深圳网站建设软件定制公司,每日财经要闻,做电脑网站,免费做简历下载的网站✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【高阶数据结构】 目录 1、图的存储结构 1.1、邻接表 1.1.1、边的结构 1.1.2、图的基本结构 1.1.3、图的创建 1.1.4、获取顶点下…

个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】【高阶数据结构】

目录

1、图的存储结构

1.1、邻接表

1.1.1、边的结构

1.1.2、图的基本结构

1.1.3、图的创建

1.1.4、获取顶点下标

1.1.5、添加边

1.1.6、打印

1.1.7、测试一

1.1.8、测试二

2、图的遍历

2.1、图的广度优先遍历

2.2、图的深度优先遍历 


1、图的存储结构

1.1、邻接表

邻接表使用数组表示顶点的集合,使用链表表示边的关系

1. 无向图邻接表存储 

注意无向图中同一条边在邻接表中出现了两次。如果想知道顶点vi的度,只需要知道顶点vi边链表集合中结点的数目即可。 

2. 有向图邻接表存储

注意:有向图中每条边在邻接表中只出现一次,与顶点vi对应的邻接表所含结点的个数,就是该顶点的出度,也称出度表,要得到vi顶点的入度,必须检测其他所有顶点对应的边链表,看有多少边顶点的dst取值是i。 

1.1.1、边的结构

1、邻接表使用链表来存储边之间的关系,因此成员需要next指针,除此之外还需要起始点(此处可以省略,因为使用目标点即可实现图)目标点权值

2、此处还需要实现一个有参构造函数参数包括目标点下标和权值

3、权值需要使用类型模板参数

template<class W>
struct Edge
{// int _srci; // 起始点,入边使用int _dsti;    // 目标点下标,出边使用W _w;        // 权值Edge<W>* _next;Edge(size_t dsti, const W& w):_dsti(dsti),_w(w),_next(nullptr){}
};

1.1.2、图的基本结构

1、使用邻接表存储图的基本结构与使用邻接矩阵存储图的基本结构类似,邻接表同样的使用模板实现,但是无需表示无穷大的非类型模板参数,因为此处为链表结构,添加边的时候才需要new新的结点

2、成员变量包括顶点集合,顶点与下标的映射关系和领接表

template<class V, class W, bool Direction = false>
class Graph
{typedef Edge<W> Edge;
public:// ...
private:vector<V> _vertexs;     // 顶点集合map<V, int> _vIndexMap; // 顶点映射下标vector<Edge*> _tables;  // 邻接表
};

1.1.3、图的创建

图的创建与邻接矩阵一样,使用手动添加边的方式创建,即实现一个有参构造(参数包含定带你集合以及顶点个数)

Graph(const V* a, size_t n)
{_vertexs.reserve(n);for (size_t i = 0; i < n; i++){_vertexs.push_back(a[i]);_vIndexMap[a[i]] = i;}_tables.resize(n, nullptr);
}

注意:此处的邻接表只需开辟一层空间,因为当添加边的时候,我们会new新的结点。

1.1.4、获取顶点下标

顶点与下标的映射存储在map中,获取顶点对应的下标只需要在map中进行查找即可,找到则返回下标,没找到则抛异常(为了编译通过,返回-1)。

// 根据顶点获取下标
size_t GetVertexIndex(const V& v)
{auto it = _vIndexMap.find(v);if (it != _vIndexMap.end()){return it->second;}else{throw invalid_argument("顶点不存在");return -1;}
}

1.1.5、添加边

1、参数为起始顶点,结束顶点和权值,还需注意有向与无向图

2、添加边的思想先获取顶点对应的下标,然后将新的结点头插到邻接表中,如果是无向图则需双向存储

void AddEdge(const V& src, const V& dst, const W& w)
{size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);// 1 -> 2 Edge* eg = new Edge(dsti, w);// 将Edge头插到邻接表eg->_next = _tables[srci];_tables[srci] = eg;// 无向图 2 -> 1if (Direction == false){Edge* eg = new Edge(srci, w);// 将Edge头插到邻接表eg->_next = _tables[dsti];_tables[dsti] = eg;}
}

1.1.6、打印

打印的方式可以根据自己需求打印,此处打印下标与顶点的映射关系和邻接表为了让打印更美观,将邻接表打印成   顶点[下标]->[顶点,下标,权值]...  的形式

void Print()
{// 顶点 下标 -> 顶点值for (size_t i = 0; i < _vertexs.size(); i++){cout << "[" << i << "]->" << _vertexs[i] << endl;}cout << endl;// 邻接表for (size_t i = 0; i < _tables.size(); i++){// 顶点[下标]->[顶点,下标,权值]...cout << _vertexs[i] << "[" << i << "]->";Edge* cur = _tables[i];while (cur){cout << "[" << _vertexs[cur->_dsti] << "," << cur->_dsti << "," << cur->_w << "]->";cur = cur->_next;}cout << "nullptr" << endl;}
}

1.1.7、测试一

顶点值为char类型。

void TestGraph1()
{Graph<char, int, true> g("0123", 4);g.AddEdge('0', '1', 1);g.AddEdge('0', '3', 4);g.AddEdge('1', '3', 2);g.AddEdge('1', '2', 9);g.AddEdge('2', '3', 8);g.AddEdge('2', '1', 5);g.AddEdge('2', '0', 3);g.AddEdge('3', '2', 6);g.Print();
}

构造函数 

添加边

打印结果

1.1.8、测试二

顶点值为string类型。

测试代码 

void TestGraph2()
{string a[] = { "张三", "李四", "王五", "赵六" };Graph<string, int, true> g1(a, 4);g1.AddEdge("张三", "李四", 100);g1.AddEdge("张三", "王五", 200);g1.AddEdge("王五", "赵六", 30);g1.Print();
}

打印结果 

2、图的遍历

注意:此处的遍历操作都是基于邻接矩阵进行遍历的。

给定一个图G和其中任意一个顶点v0,从v0出发,沿着图中各边访问图中的所有顶点,且每个顶点仅被遍历一次"遍历"即对结点进行某种操作的意思

2.1、图的广度优先遍历

如何防止节点被重复遍历?

我们可以创建一个标记容器成员类型为bool类型,访问过则将值设置为true,默认为false。 

广度优先遍历思想:

与二叉树的层序遍历类似,需要借助队列先将第一个值入队列,出队列的同时把邻接顶点入队,直到队列为空则遍历结束,具体步骤如下:

  • 1、获取顶点对应的下标
  • 2、创建队列和标记容器
  • 3、入队
  • 4、队列不为空则遍历
    • 4.1、打印队头
    • 4.2、将front的邻接顶点入队
      • 有效边且标志位为false则入队

遍历代码 

// 根据顶点进行广度优先遍历,使用队列+标记容器
void BFS(const V& src)
{// 1.获取顶点对应的下标size_t srci = GetVertexIndex(src);// 2.创建队列和标记容器queue<int> q;vector<bool> visited(_vertexs.size(),false); // 默认false可以访问// 3.入队q.push(srci);visited[srci] = true; // 不能访问size_t n = _vertexs.size();// 4.队列不为空则遍历while (!q.empty()){// 打印队头int front = q.front();q.pop();cout << front << ":" << _vertexs[front] << endl;// 将front的邻接顶点入队for (size_t i = 0; i < n; i++){// 有效边且标志位为false则入队if (_matrix[front][i] != MAX_W && !visited[i]){q.push(i);visited[i] = true;}}}cout << endl;
}

测试代码

void TestBDFS()
{string a[] = { "张三", "李四", "王五", "赵六", "周七" };Graph<string, int> g1(a, sizeof(a) / sizeof(string));g1.AddEdge("张三", "李四", 100);g1.AddEdge("张三", "王五", 200);g1.AddEdge("王五", "赵六", 30);g1.AddEdge("王五", "周七", 30);g1.Print();g1.BFS("张三");
}

结构及打印结果

遍历结果

上面确实实现了广度优先遍历,但是能不能像二叉树的层序遍历一样,打印每一层呢?

可以的。

与二叉树打印每一层类型,我们可以创建一个记录队列元素个数的变量,一次打印队列元素个数个,打印完一层之后更新这个值

一层层打印 

// 广度优先遍历(一层层打印)
void BFS(const V& src)
{// 1.获取顶点对应的下标size_t srci = GetVertexIndex(src);// 2.创建队列和标记容器queue<int> q;vector<bool> visited(_vertexs.size(), false); // 默认false可以访问// 3.入队q.push(srci);visited[srci] = true; // 不能访问int levelSize = 1;size_t n = _vertexs.size();// 4.队列不为空则遍历while (!q.empty()){// 一层层打印,一次打印队列个数个for (int i = 0; i < levelSize; i++){// 打印队头int front = q.front();q.pop();cout << front << ":" << _vertexs[front] << endl;// 将front的邻接顶点入队for (size_t i = 0; i < n; i++){// 有效边且标志位为false则入队if (_matrix[front][i] != MAX_W && !visited[i]){q.push(i);visited[i] = true;}}}cout << endl;levelSize = q.size();}
}

遍历结果 

2.2、图的深度优先遍历 

深度优先遍历思想: 

与二叉树的前序遍历类似,但是此处需要使用标记容器,因此需要实现一个子函数具体步骤如下:

  • 1、获取顶点对应的下标
  • 2、创建标记容器
  • 3、调用子函数

子函数思想:

  • 1、打印该位置的值并将该位置的标记位设置为true(不能再访问)
  • 2、找一个该位置相邻的且没有访问过的点深度遍历

代码实现 

void _DFS(size_t srci, vector<bool>& visited)
{// 下标:顶点值cout << srci << ":" << _vertexs[srci] << endl;visited[srci] = true; // 不能再访问// 找一个scri相邻的且没有访问过的点,深度遍历for (size_t i = 0; i < _vertexs.size(); i++){if (_matrix[srci][i] != MAX_W && !visited[i]){_DFS(i, visited);}}
}
void DFS(const V& src)
{size_t srci = GetVertexIndex(src);vector<bool> visited(_vertexs.size(), false);_DFS(srci, visited);
}

运行结果

http://www.dtcms.com/wzjs/484796.html

相关文章:

  • 合肥做网站哪家好百度关键词广告怎么收费
  • asp动态网站制作网站外部优化的4大重点
  • 做可视化图表的网站宁德市是哪个省
  • 筑方装饰口碑怎么样手机网络优化软件
  • 设计与绘制一个网站首页河南网站建设定制
  • 网站框架怎么建设关键词网站排名查询
  • 网站做的自适应体验差怎么自己开网站
  • 怎么做钓鱼网站生成常用的网络营销平台有哪些
  • 网站做百度推广为什么没人咨询网页制作代码大全
  • 深圳高端网站建设网页设计seo优化厂商
  • 做网站需要写代码吗国内做seo最好公司
  • 个人备案 做政府网站seoul怎么读
  • 备案网站名称更改市场调研的五个步骤
  • 做动态头像的网站roseonly企业网站优化
  • 公司的网站建设做什么费用职业技能培训班
  • 0建设营销型网站步骤介绍企业网站怎么注册官网
  • 网站建设申报书火星时代教育培训机构学费多少
  • 长春市长春网站建设哪家好手机如何建网站
  • 企业网站怎么做推广比较好360seo优化
  • 柳州房地产网站建设百度广告位价格表
  • 无锡做装修网站网推
  • 外链发布平台有哪些国内seo公司排名
  • 济南专业网站开发公司百度seo培训课程
  • 承接设计网站建设网站开发工具
  • axure能不能直接做网站查域名
  • 做网站要学什么软件如何建站
  • nas装wordpress搜索引擎优化主要包括
  • dedecms网站后台济南百度代理
  • 网站建设淘宝走流程深圳十大网络推广公司排名
  • 国产成年做视频网站google浏览器官网