C++ Boost Graph算法超详细精讲

Boost.Graph 中的算法类似于标准库中的算法——它们是通用的并且非常灵活。但是,并不总是很清楚应该如何使用它们。

示例 31.8。使用breadth_first_search() 从内到外访问点

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/array.hpp>
#include <array>
#include <utility>
#include <iterator>
#include <algorithm>
#include <iostream>
int main()
{
  enum { topLeft, topRight, bottomRight, bottomLeft };
  std::array<std::pair<int, int>, 4> edges{{
    std::make_pair(topLeft, topRight),
    std::make_pair(topRight, bottomRight),
    std::make_pair(bottomRight, bottomLeft),
    std::make_pair(bottomLeft, topLeft)
  }};
  typedef boost::adjacency_list<boost::setS, boost::vecS,
    boost::undirectedS> graph;
  graph g{edges.begin(), edges.end(), 4};
  boost::array<int, 4> distances{{0}};
  boost::breadth_first_search(g, topLeft,
    boost::visitor(
      boost::make_bfs_visitor(
        boost::record_distances(distances.begin(),
          boost::on_tree_edge{}))));
  std::copy(distances.begin(), distances.end(),
    std::ostream_iterator<int>{std::cout, "\n"});
}

Example31.8

示例 31.8 使用算法 boost::breadth_first_search() 从内部到外部访问点。该算法从作为第二个参数传递的点开始。它首先访问可以从该点直接到达的所有点,像波浪一样工作。

boost::breadth_first_search() 不返回特定结果。该算法只是访问点。是否收集和存储数据取决于传递给 boost::breadth_first_search() 的访问者。

访问者是在访问点时调用其成员函数的对象。通过将访问者传递给 boost::breadth_first_search() 之类的算法,您可以决定访问某个点时应该发生什么。访问者就像函数对象,可以传递给标准库的算法。

示例 31.8 使用记录距离的访问者。距离是从一个点到另一个点必须跨越的线数,从作为第二个参数传递给 boost::breadth_first_search() 的点开始。 Boost.Graph 提供了帮助函数 boost::record_distances() 来创建访问者。还必须传递属性图和标签。

属性映射存储点或线的属性。 Boost.Graph 描述了属性映射的概念。由于指针或迭代器被视为属性映射的开头,因此详细了解属性映射并不重要。在示例 31.8 中,数组距离的开头通过 distances.begin() 传递到 boost::record_distances()。这足以将数组距离用作属性映射。但是,重要的是数组的大小不小于图中的点数。毕竟,需要存储到图中每个点的距离。

请注意,距离基于 boost::array 而不是 std::array。使用 std::array 会导致编译器错误。

根据算法,有不同的事件。传递给 boost::record_distances() 的第二个参数指定应通知访问者哪些事件。 Boost.Graph 定义了空类的标签来给事件命名。示例 31.8 中的标签 boost::on_tree_edge 指定在找到新点时应记录距离。

事件取决于算法。您必须查看有关算法的文档,以了解支持哪些事件以及可以使用哪些标签。

由 boost::record_distances() 创建的访问者与算法无关,因此您可以将 boost::record_distances() 与其他算法一起使用。适配器用于绑定算法和访问者。示例 31.8 调用 boost::make_bfs_visitor() 来创建这个适配器。此帮助函数返回算法 boost::breadth_first_search() 所期望的访问者。此访问者定义适合算法支持的事件的成员函数。例如,boost::make_bfs_visitor() 返回的访问者定义了成员函数 tree_edge()。如果使用标签 boost::on_tree_edge 定义的访问者被传递给 boost::make_bfs_visitor()(如示例 31.8),则在调用 tree_edge() 时会通知访问者。这使您可以使用具有不同算法的访问者,而无需这些访问者定义所有算法所期望的所有成员函数。

boost::make_bfs_visitor() 返回的适配器不能直接传递给算法 boost::breadth_first_search()。它必须用 boost::visitor() 包装,然后作为第三个参数传递。

有两种算法变体,例如 boost::breadth_first_search()。一种变体期望算法支持的每个参数都将被传递。另一个变体支持类似于命名参数的东西。使用第二个变体通常更容易,因为只需要传递您感兴趣的参数。许多参数不必传递,因为算法使用默认值。

示例 31.8 使用了需要命名参数的 boost::breadth_first_search() 的变体。前两个参数是图形和起点,它们是必需的。然而,第三个参数几乎可以是一切。在示例 31.8 中,需要传递一个访问者。为此,boost::make_bfs_visitor() 返回的适配器使用 boost::visitor() 命名。现在,很明显第三个参数是访问者。您将在以下示例中看到其他参数如何按名称传递到 boost::breadth_first_search()。

示例 31.8 显示数字 0、1、2 和 1。这些是从左上角到所有点的距离。右上角的字段(索引为 1 的字段)仅一步之遥。右下方的字段(索引为 2 的字段)相距两步。左下方的字段——索引为 3 的字段——再次只有一步之遥。首先打印的数字 0 是指左上角的字段。由于它是传递给 boost::breadth_first_search() 的起点,因此需要零步才能到达它。

boost::breadth_first_search() 不设置数组中的元素,它只是增加存储的值。因此,您必须在开始之前初始化数组距离中的所有元素。

示例 31.9 说明了如何找到最短路径。

示例 31.9。使用 width_first_search() 查找路径

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/array.hpp>
#include <array>
#include <utility>
#include <algorithm>
#include <iostream>
int main()
{
  enum { topLeft, topRight, bottomRight, bottomLeft };
  std::array<std::pair<int, int>, 4> edges{{
    std::make_pair(topLeft, topRight),
    std::make_pair(topRight, bottomRight),
    std::make_pair(bottomRight, bottomLeft),
    std::make_pair(bottomLeft, topLeft)
  }};
  typedef boost::adjacency_list<boost::setS, boost::vecS,
    boost::undirectedS> graph;
  graph g{edges.begin(), edges.end(), 4};
  boost::array<int, 4> predecessors;
  predecessors[bottomRight] = bottomRight;
  boost::breadth_first_search(g, bottomRight,
    boost::visitor(
      boost::make_bfs_visitor(
        boost::record_predecessors(predecessors.begin(),
          boost::on_tree_edge{}))));
  int p = topLeft;
  while (p != bottomRight)
  {
    std::cout << p << '\n';
    p = predecessors[p];
  }
  std::cout << p << '\n';
}

Example31.9

示例 31.9 显示 0、1 和 2。这是从左上角到右下角的最短路径。尽管左下场上的路径同样短,但它在右上场上方引导。

再次使用 boost::breadth_first_search() - 这次是为了找到最短路径。如您所知,此算法只是访问点。要获得最短路径的描述,必须使用适当的访问者。示例 31.9 调用 boost::record_predecessors() 来获取一个。

boost::record_predecessors() 返回一个访问者来存储每个点的前任。每当 boost::breadth_first_search() 访问一个新点时,前一个点就会存储在传递给 boost::record_predecessors() 的属性映射中。由于 boost::breadth_first_search() 从内部到外部访问点,因此找到了最短路径——从作为第二个参数传递给 boost::breadth_first_search() 的点开始。示例 31.9 找到从图中所有点到右下角的最短路径。

在 boost::breadth_first_search() 返回后,属性映射前驱包含每个点的前驱。为了在从左上角到右下角时找到第一个字段,索引为 0 的元素(左上角字段的索引)在前辈中被访问。在前辈中找到的值为 1,这意味着下一个字段位于右上角。访问索引为 1 的前辈会返回下一个字段。在示例 31.9 中,这是右下角的字段 - 索引为 2 的字段。这样就可以在巨大的图表中迭代地找到从起点到终点的点。

示例 31.10。使用 width_first_search() 查找距离和路径

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/breadth_first_search.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/graph/visitors.hpp>
#include <boost/array.hpp>
#include <array>
#include <utility>
#include <algorithm>
#include <iostream>
int main()
{
  enum { topLeft, topRight, bottomRight, bottomLeft };
  std::array<std::pair<int, int>, 4> edges{{
    std::make_pair(topLeft, topRight),
    std::make_pair(topRight, bottomRight),
    std::make_pair(bottomRight, bottomLeft),
    std::make_pair(bottomLeft, topLeft)
  }};
  typedef boost::adjacency_list<boost::setS, boost::vecS,
    boost::undirectedS> graph;
  graph g{edges.begin(), edges.end(), 4};
  boost::array<int, 4> distances{{0}};
  boost::array<int, 4> predecessors;
  predecessors[bottomRight] = bottomRight;
  boost::breadth_first_search(g, bottomRight,
    boost::visitor(
      boost::make_bfs_visitor(
        std::make_pair(
          boost::record_distances(distances.begin(),
            boost::on_tree_edge()),
          boost::record_predecessors(predecessors.begin(),
            boost::on_tree_edge{})))));
  std::for_each(distances.begin(), distances.end(),
    [](int d){ std::cout << d << '\n'; });
  int p = topLeft;
  while (p != bottomRight)
  {
    std::cout << p << '\n';
    p = predecessors[p];
  }
  std::cout << p << '\n';
}

Example31.10

示例 31.10 显示了 boost::breadth_first_search() 如何用于两个访问者。要使用两个访问者,您需要使用 std::make_pair() 将它们配对。如果需要两个以上的访问者,则必须嵌套这些对。示例 31.10 与示例 31.8 和示例 31.9 一起执行相同的操作。

boost::breadth_first_search() 只能在每行具有相同权重的情况下使用。这意味着跨越点之间的任何线所花费的时间总是相同的。如果线是加权的,这意味着每条线可能需要不同的时间来遍历,那么您需要使用不同的算法来找到最短路径。

示例 31.11。使用 dijkstra_shortest_paths() 查找路径

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/array.hpp>
#include <array>
#include <utility>
#include <iostream>
int main()
{
  enum { topLeft, topRight, bottomRight, bottomLeft };
  std::array<std::pair<int, int>, 4> edges{{
    std::make_pair(topLeft, topRight),
    std::make_pair(topRight, bottomRight),
    std::make_pair(bottomRight, bottomLeft),
    std::make_pair(bottomLeft, topLeft)
  }};
  typedef boost::adjacency_list<boost::listS, boost::vecS,
    boost::undirectedS, boost::no_property,
    boost::property<boost::edge_weight_t, int>> graph;
  std::array<int, 4> weights{{2, 1, 1, 1}};
  graph g{edges.begin(), edges.end(), weights.begin(), 4};
  boost::array<int, 4> directions;
  boost::dijkstra_shortest_paths(g, bottomRight,
    boost::predecessor_map(directions.begin()));
  int p = topLeft;
  while (p != bottomRight)
  {
    std::cout << p << '\n';
    p = directions[p];
  }
  std::cout << p << '\n';
}

Example31.11

示例 31.11 使用 boost::dijkstra_shortest_paths() 来查找到右下角的最短路径。如果线被加权,则使用此算法。示例 31.11 假设从左上角到右上角越过线所需的时间是越过任何其他线所需的时间的两倍。

在使用 boost::dijkstra_shortest_paths() 之前,必须将权重分配给行。这是通过数组权重完成的。数组中的元素对应于图中的线条。因为从左上角到右上角的线是第一个,所以 weights 中的第一个元素被设置为所有其他元素的两倍大。

为了给线条分配权重,数组权重开头的迭代器作为第三个参数传递给图形的构造函数。这第三个参数可用于初始化线条的属性。这仅适用于已为线条定义属性的情况。

示例 31.11 将其他模板参数传递给 boost::adjacency_list。第四个和第五个模板参数指定点和线是否具有属性以及这些属性是什么。您可以为线和点指定属性。

默认情况下,boost::adjacency_list 使用 boost::no_property,这意味着点和线都没有属性。在示例 31.11 中,boost::no_property 作为第四个参数传递,用于指定点的无属性。第五个参数使用 boost::property 定义捆绑属性。

捆绑属性是内部存储在图表中的属性。因为可以定义多个捆绑属性,所以 boost::property 需要一个标签来定义每个属性。 Boost.Graph 提供了一些标签,例如 boost::edge_weight_t,来定义算法自动识别和使用的常用属性。传递给 boost::property 的第二个模板参数是属性的类型。在示例 31.11 中,权重是 int 值。

示例 31.11 有效,因为 boost::dijkstra_shortest_paths() 自动使用类型为 boost::edge_weight_t 的捆绑属性。

请注意,没有访问者被传递到 boost::dijkstra_shortest_paths()。该算法不只是访问点。它寻找最短路径——这就是为什么它被称为 boost::dijkstra_shortest_paths()。您无需考虑事件或访客。你只需要传递一个容器来存储每个点的前身。如果您使用需要命名参数的 boost::dijkstra_shortest_paths() 变体,如示例 31.11 中所示,则使用 boost::predecessor_map() 传递容器。这是一个辅助函数,它需要一个指向数组开头的指针或迭代器。

示例 31.11 显示 0、3 和 2:从左上角到右下角的最短路径通向左下角字段。右上角的路径比其他可能性具有更大的权重。

示例 31.12。使用 dijkstra_shortest_paths() 的用户定义属性

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/array.hpp>
#include <array>
#include <utility>
#include <iostream>
int main()
{
  enum { topLeft, topRight, bottomRight, bottomLeft };
  std::array<std::pair<int, int>, 4> edges{{
    std::make_pair(topLeft, topRight),
    std::make_pair(topRight, bottomRight),
    std::make_pair(bottomRight, bottomLeft),
    std::make_pair(bottomLeft, topLeft)
  }};
  struct edge_properties
  {
    int weight;
  };
  typedef boost::adjacency_list<boost::listS, boost::vecS,
    boost::undirectedS, boost::no_property,
    edge_properties> graph;
  graph g{edges.begin(), edges.end(), 4};
  graph::edge_iterator it, end;
  boost::tie(it, end) = boost::edges(g);
  g[*it].weight = 2;
  g[*++it].weight = 1;
  g[*++it].weight = 1;
  g[*++it].weight = 1;
  boost::array<int, 4> directions;
  boost::dijkstra_shortest_paths(g, bottomRight,
    boost::predecessor_map(directions.begin()).
    weight_map(boost::get(&edge_properties::weight, g)));
  int p = topLeft;
  while (p != bottomRight)
  {
    std::cout << p << '\n';
    p = directions[p];
  }
  std::cout << p << '\n';
}

Example31.12

示例 31.12 的工作方式与上一个类似,并显示相同的数字,但它使用用户定义的类 edge_properties,而不是预定义的属性。

edge_properties 定义成员变量 weight 来存储线条的重量。如果需要其他属性,可以添加更多成员变量。

如果您使用线的描述符作为图形的索引,则可以访问用户定义的属性。因此,该图的行为类似于一个数组。您从 boost::edges() 返回的行迭代器中获取描述符。这样就可以为每一行分配一个权重。

为了让 boost::dijkstra_shortest_paths() 理解权重存储在 edge_properties 中的权重中,必须传递另一个命名参数。这是通过 weight_map() 完成的。请注意,weight_map() 是从 boost::predecessor_map() 返回的对象的成员函数。还有一个名为 boost::weight_map() 的独立函数。如果需要传递多个命名参数,则必须在第一个命名参数(独立函数返回的参数)上调用成员函数。这样,所有参数都被打包到一个对象中,然后传递给算法。

为了告诉 boost::dijkstra_shortest_paths() edge_properties 中的权重包含权重,传递了一个指向该属性的指针。它不会直接传递给 weight_map()。相反,它通过 boost::get() 创建的对象传递。现在调用已完成,并且 boost::dijkstra_shortest_paths() 知道要访问哪个属性来获取权重。

示例 31.13。在图形定义处初始化用户定义的属性

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/named_function_params.hpp>
#include <boost/array.hpp>
#include <array>
#include <utility>
#include <iostream>
int main()
{
  enum { topLeft, topRight, bottomRight, bottomLeft };
  std::array<std::pair<int, int>, 4> edges{{
    std::make_pair(topLeft, topRight),
    std::make_pair(topRight, bottomRight),
    std::make_pair(bottomRight, bottomLeft),
    std::make_pair(bottomLeft, topLeft)
  }};
  struct edge_properties
  {
    int weight;
  };
  typedef boost::adjacency_list<boost::listS, boost::vecS,
    boost::undirectedS, boost::no_property,
    edge_properties> graph;
  boost::array<edge_properties, 4> props{{2, 1, 1, 1}};
  graph g{edges.begin(), edges.end(), props.begin(), 4};
  boost::array<int, 4> directions;
  boost::dijkstra_shortest_paths(g, bottomRight,
    boost::predecessor_map(directions.begin()).
    weight_map(boost::get(&edge_properties::weight, g)));
  int p = topLeft;
  while (p != bottomRight)
  {
    std::cout << p << '\n';
    p = directions[p];
  }
  std::cout << p << '\n';
}

定义图形时可以初始化用户定义的属性。您只需将迭代器作为第三个参数传递给 boost::adjacency_list 的构造函数,它引用用户定义属性类型的对象。因此,您不需要通过描述符访问行的属性。示例 31.13 的工作原理与前一个类似,并显示相同的结果。

示例 31.14。带有 random_spanning_tree() 的随机路径

示例 31.14 中介绍的算法会找到随机路径。 boost::random_spanning_tree() 类似于 boost::dijkstra_shortest_paths()。它返回通过 boost::predecessor_map 传递的容器中的点的前驱。与 boost::dijkstra_shortest_paths() 相比,起点不直接作为参数传递给 boost::random_spanning_tree()。它必须作为命名参数传递。这就是为什么在 boost::predecessor_map 类型的对象上调用 root_vertex()。示例 31.14 查找到左下角字段的随机路径。

因为 boost::random_spanning_tree() 正在寻找随机路径,所以必须将随机数生成器作为第二个参数传递。示例 31.14 使用 std::mt19937,它自 C++11 以来一直是标准库的一部分。您还可以使用 Boost.Random 中的随机数生成器。

示例 31.14 显示 1、0 和 3 或 1、2 和 3。1 是右上角的字段,3 是左下角的字段。从右上场到左下场只有两种可能的路径:通过左上场或通过右下场。 boost::random_spanning_tree() 必须返回这两个路径之一。

练习

为以下国家/地区创建具有顶点的图形:荷兰、比利时、法国、德国、瑞士、奥地利和意大利。用共同边界连接这些国家的顶点。找到从意大利到荷兰的最短路径——过境次数最少的路径。将所有国家/地区的名称写入您从意大利到荷兰的途中经过的标准输出。

扩展您的计划:现在进入法国花费 10 欧元,进入比利时 15 欧元,进入德国 20 欧元。跨越所有其他边界仍然是免费的。找到最短的路径——过境点最少的路径——这也是从意大利到荷兰的最便宜的路径。将所有国家/地区的名称写入您从意大利到荷兰的途中经过的标准输出。

到此这篇关于C++ Boost Graph算法超详细精讲的文章就介绍到这了,更多相关C++ Boost Graph 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ Boost Algorithm算法超详细精讲

    目录 一.说明Boost.Algorithm 二.示例 练习 一.说明Boost.Algorithm Boost.Algorithm 请注意,其他 Boost 库提供了许多算法.例如,您会在 Boost.StringAlgorithms 中找到处理字符串的算法. Boost.Algorithm 提供的算法不受特定类的约束,例如 std::string.与标准库中的算法一样,它们可以与任何容器一起使用. 二.示例 示例 29.1.使用 boost::algorithm::one_of_equal(

  • C++ Boost Bimap示例详细讲解

    目录 一.提要 二.示例 练习 一.提要 库 Boost.Bimap 基于 Boost.MultiIndex 并提供了一个无需先定义即可立即使用的容器.该容器类似于 std::map,但支持从任一侧查找值. Boost.Bimap 允许您根据访问地图的方式创建任意一侧都可以作为关键点的地图.当您访问左侧作为键时,右侧是值,反之亦然. 二.示例 Example13.1.Usingboost::bimap #include <boost/bimap.hpp> #include <string

  • C++ Boost CircularBuffer算法超详细精讲

    提要 库 Boost.CircularBuffer 提供了一个循环缓冲区,它是一个具有以下两个基本属性的容器: 循环缓冲区的容量是恒定的,由您设置.当您调用成员函数(例如 push_back())时,容量不会自动更改.只有您可以更改循环缓冲区的容量.循环缓冲区的大小不能超过您设置的容量. 尽管容量不变,但您可以随时调用 push_back() 将元素插入循环缓冲区.如果已达到最大大小并且循环缓冲区已满,则将覆盖元素. 当可用内存量有限并且您需要防止容器任意增长时,循环缓冲区是有意义的.另一个例子

  • C++ Boost.Range与Adapters库使用详解

    目录 一.说明 二.适配器 练习 一.说明 本节叙述关于Boost.Range和Adeptor两个内容. Boost.Range 是一个库,乍一看,它提供的算法类似于标准库提供的算法.例如,您会发现函数 boost::copy(),它的作用与 std::copy() 相同.但是, std::copy() 需要两个参数,而 boost::copy() 需要一个范围. 二.适配器 标准库提供了几种可以传递谓词的算法.例如,传递给 std::count_if() 的谓词确定计算哪些元素. Boost.

  • C++ Boost MultiArray简化使用多维数组库

    目录 一.介绍Boost.MultiArray 二.示例 一.介绍Boost.MultiArray Boost.MultiArray Boost.MultiArray 是一个简化使用多维数组的库.最重要的优点是多维数组可以像标准库中的容器一样使用.例如,有一些成员函数,例如 begin() 和 end(),让您可以通过迭代器访问多维数组中的元素.迭代器比通常用于 C 数组的指针更易于使用,尤其是对于具有多个维度的数组. 二.示例 示例 19.1.带有 boost::multi_array 的一维

  • C++ Boost Heap使用实例详解

    目录 一.说明Boost.Heap 二.功能示例 一.说明Boost.Heap Boost.Heap 也可以称为 Boost.PriorityQueue,因为该库提供了几个优先级队列.但是,Boost.Heap 中的优先级队列与 std::priority_queue 不同,它支持更多功能. 二.功能示例 示例 17.1.使用 boost::heap::priority_queue #include <boost/heap/priority_queue.hpp> #include <io

  • C++ Boost Intrusive库示例精讲

    目录 一.说明 二.示例 一.说明 Boost.Intrusive 是一个特别适合在高性能程序中使用的库.该库提供了创建侵入式容器的工具.这些容器替换了标准库中的已知容器.它们的缺点是它们不能像 std::list 或 std::set 那样容易使用.但它们有以下优点: 侵入式容器不会动态分配内存.对 push_back() 的调用不会导致使用 new 进行动态分配.这是侵入式容器可以提高性能的一个原因. 侵入式容器不会动态分配内存.对 push_bacIntrusive 容器的调用存储原始对象

  • C++ Boost Graph算法超详细精讲

    Boost.Graph 中的算法类似于标准库中的算法——它们是通用的并且非常灵活.但是,并不总是很清楚应该如何使用它们. 示例 31.8.使用breadth_first_search() 从内到外访问点 #include <boost/graph/adjacency_list.hpp> #include <boost/graph/breadth_first_search.hpp> #include <boost/graph/named_function_params.hpp&

  • C++可扩展性与多线程超详细精讲

    目录 一.可扩展性和多线程 二.线程示例 一.可扩展性和多线程 基于 Boost.Asio 之类的库开发程序与通常的 C++ 风格不同.可能需要更长时间才能返回的函数不再按顺序调用. Boost.Asio 不调用阻塞函数,而是启动异步操作.操作完成后应该调用的函数现在在相应的处理程序中调用.这种方法的缺点是顺序执行函数的物理分离,这会使代码更难理解. 诸如 Boost.Asio 之类的库通常用于实现更高的效率.无需等待操作完成,程序可以在其间执行其他任务.因此,可以启动多个同时执行的异步操作——

  • Java贪心算法超详细讲解

    目录 什么是贪心算法 通过场景理解算法 问题分析 总结 什么是贪心算法 在分析和求解某个问题时,在每一步的计算选择上都是最优的或者最好的,通过这种方式期望最终的计算的结果也是最优的.也就是说,算法通过先追求局部的最优解,从而寻求整体的最优解. 贪心算法的基本步骤: 1.首先定义问题,确定问题模型是不是适合使用贪心算法,即求解最值问题: 2.将求极值的问题进行拆解,然后对拆解后的每一个子问题进行求解,试图获得当前子问题的局部最优解: 3.所有子问题的局部最优解求解完成后,把这些局部最优解进行汇总合

  • Java超详细精讲数据结构之bfs与双端队列

    目录 一.bfs 二.双端队列 三.算法题 1.kotori和迷宫 2.小红找红点 3.小红玩数组 一.bfs bfs(广度优先搜索),类似二叉树的层序遍历,利用队列完成.一般用于求最短路. 图的最短路问题: 给定一个无向图,每条边的长度都是1.求1号点到x号点的最短距离. 顶点数n 边数为m q次询问 输入x 输出1到x的最短距离. 若1号点到x不连通,则输出-1 二.双端队列 双端队列的应用(区间翻转): 对于长度为n的数组,给定一个长度为m的区间,区间初始位置为a[1]到a[m]. 3种操

  • C++模板的特化超详细精讲

    目录 一.泛型编程 二.函数模板 2.1.函数模板的概念 2.2.函数模板的格式 2.3.函数模板的原理 2.4.函数模板的实例化 2.4.1.隐式实例化 2.4.2.显示实例化 三.类模板 3.1.类模板的定义格式 3.1.类模板的实例化 四.模板的特化 4.1.概念 4.2.函数模板特化步骤 4.3.类模板的特化 4.3.1.全特化 4.3.2.偏特化 一.泛型编程 我们前面已经学过函数的重载,实现了在函数名相同的情况下,实现不同的功能! 例如: void Swap(int& left, i

  • Java BOI与NIO超详细实例精讲

    目录 Java BIO 示例代码 Java NIO 代码解读 Java BIO 阻塞IO,每个客户端链接都需要一个独立的线程处理,客户端链接没关闭时,线程链接处于阻塞状态,直到客户端链接关闭 如果客户端链接没有读取到数据,链接就会一直阻塞住,造成资源浪费 示例代码 开发一个ServerSocket服务端,通过telnet链接发送信息 import java.io.IOException; import java.io.InputStream; import java.net.ServerSock

  • MySQL数据库索引order by排序精讲

    排序这个词,我的第一感觉是几乎所有App都有排序的地方,淘宝商品有按照购买时间的排序.B站的评论有按照热度排序的... 对于MySQL,一说到排序,你第一时间想到的是什么?关键字order by?order by的字段最好有索引?叶子结点已经是顺序的?还是说尽量不要在MySQL内部排序? 事情的起因 现在假设有一张用户的朋友表: CREATE TABLE `user` ( `id` int(10) AUTO_INCREMENT, `user_id` int(10), `friend_addr`

随机推荐