boost_web_graph.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. //=======================================================================
  2. // Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
  3. // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //=======================================================================
  9. #include <boost/config.hpp>
  10. #include <iostream>
  11. #include <fstream>
  12. #include <string>
  13. #include <algorithm>
  14. #include <map>
  15. #include <boost/pending/stringtok.hpp>
  16. #include <boost/utility.hpp>
  17. #include <boost/graph/adjacency_list.hpp>
  18. #include <boost/graph/visitors.hpp>
  19. #include <boost/graph/breadth_first_search.hpp>
  20. #include <boost/graph/depth_first_search.hpp>
  21. template <class Distance>
  22. class calc_distance_visitor : public boost::bfs_visitor<>
  23. {
  24. public:
  25. calc_distance_visitor(Distance d) : distance(d) { }
  26. template <class Graph>
  27. void tree_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
  28. Graph& g)
  29. {
  30. typename boost::graph_traits<Graph>::vertex_descriptor u, v;
  31. u = boost::source(e, g);
  32. v = boost::target(e, g);
  33. distance[v] = distance[u] + 1;
  34. }
  35. private:
  36. Distance distance;
  37. };
  38. template <class VertexNameMap, class DistanceMap>
  39. class print_tree_visitor : public boost::dfs_visitor<>
  40. {
  41. public:
  42. print_tree_visitor(VertexNameMap n, DistanceMap d) : name(n), distance(d) { }
  43. template <class Graph>
  44. void
  45. discover_vertex(typename boost::graph_traits<Graph>::vertex_descriptor v,
  46. Graph&)
  47. {
  48. typedef typename boost::property_traits<DistanceMap>::value_type Dist;
  49. // indentation based on depth
  50. for (Dist i = 0; i < distance[v]; ++i)
  51. std::cout << " ";
  52. std::cout << name[v] << std::endl;
  53. }
  54. template <class Graph>
  55. void tree_edge(typename boost::graph_traits<Graph>::edge_descriptor e,
  56. Graph& g)
  57. {
  58. distance[boost::target(e, g)] = distance[boost::source(e, g)] + 1;
  59. }
  60. private:
  61. VertexNameMap name;
  62. DistanceMap distance;
  63. };
  64. int
  65. main(int argc, const char** argv)
  66. {
  67. using namespace boost;
  68. std::ifstream datafile(argc >= 2 ? argv[1] : "./boost_web.dat");
  69. if (!datafile) {
  70. std::cerr << "No ./boost_web.dat file" << std::endl;
  71. return -1;
  72. }
  73. //===========================================================================
  74. // Declare the graph type and object, and some property maps.
  75. typedef adjacency_list<vecS, vecS, directedS,
  76. property<vertex_name_t, std::string,
  77. property<vertex_color_t, default_color_type> >,
  78. property<edge_name_t, std::string, property<edge_weight_t, int> >
  79. > Graph;
  80. typedef graph_traits<Graph> Traits;
  81. typedef Traits::vertex_descriptor Vertex;
  82. typedef Traits::edge_descriptor Edge;
  83. typedef std::map<std::string, Vertex> NameVertexMap;
  84. NameVertexMap name2vertex;
  85. Graph g;
  86. typedef property_map<Graph, vertex_name_t>::type NameMap;
  87. NameMap node_name = get(vertex_name, g);
  88. property_map<Graph, edge_name_t>::type link_name = get(edge_name, g);
  89. //===========================================================================
  90. // Read the data file and construct the graph.
  91. std::string line;
  92. while (std::getline(datafile,line)) {
  93. std::list<std::string> line_toks;
  94. boost::stringtok(line_toks, line, "|");
  95. NameVertexMap::iterator pos;
  96. bool inserted;
  97. Vertex u, v;
  98. std::list<std::string>::iterator i = line_toks.begin();
  99. boost::tie(pos, inserted) = name2vertex.insert(std::make_pair(*i, Vertex()));
  100. if (inserted) {
  101. u = add_vertex(g);
  102. put(node_name, u, *i);
  103. pos->second = u;
  104. } else
  105. u = pos->second;
  106. ++i;
  107. std::string hyperlink_name = *i++;
  108. boost::tie(pos, inserted) = name2vertex.insert(std::make_pair(*i, Vertex()));
  109. if (inserted) {
  110. v = add_vertex(g);
  111. put(node_name, v, *i);
  112. pos->second = v;
  113. } else
  114. v = pos->second;
  115. Edge e;
  116. boost::tie(e, inserted) = add_edge(u, v, g);
  117. if (inserted) {
  118. put(link_name, e, hyperlink_name);
  119. }
  120. }
  121. //===========================================================================
  122. // Calculate the diameter of the graph.
  123. typedef Traits::vertices_size_type size_type;
  124. typedef std::vector<size_type> IntVector;
  125. // Create N x N matrix for storing the shortest distances
  126. // between each vertex. Initialize all distances to zero.
  127. std::vector<IntVector> d_matrix(num_vertices(g),
  128. IntVector(num_vertices(g), 0));
  129. size_type i;
  130. for (i = 0; i < num_vertices(g); ++i) {
  131. calc_distance_visitor<size_type*> vis(&d_matrix[i][0]);
  132. Traits::vertex_descriptor src = vertices(g).first[i];
  133. breadth_first_search(g, src, boost::visitor(vis));
  134. }
  135. size_type diameter = 0;
  136. BOOST_USING_STD_MAX();
  137. for (i = 0; i < num_vertices(g); ++i)
  138. diameter = max BOOST_PREVENT_MACRO_SUBSTITUTION(diameter, *std::max_element(d_matrix[i].begin(),
  139. d_matrix[i].end()));
  140. std::cout << "The diameter of the boost web-site graph is " << diameter
  141. << std::endl << std::endl;
  142. std::cout << "Number of clicks from the home page: " << std::endl;
  143. Traits::vertex_iterator vi, vi_end;
  144. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  145. std::cout << d_matrix[0][*vi] << "\t" << node_name[*vi] << std::endl;
  146. std::cout << std::endl;
  147. //===========================================================================
  148. // Print out the breadth-first search tree starting at the home page
  149. // Create storage for a mapping from vertices to their parents
  150. std::vector<Traits::vertex_descriptor> parent(num_vertices(g));
  151. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  152. parent[*vi] = *vi;
  153. // Do a BFS starting at the home page, recording the parent of each
  154. // vertex (where parent is with respect to the search tree).
  155. Traits::vertex_descriptor src = vertices(g).first[0];
  156. breadth_first_search
  157. (g, src,
  158. boost::visitor(make_bfs_visitor(record_predecessors(&parent[0],
  159. on_tree_edge()))));
  160. // Add all the search tree edges into a new graph
  161. Graph search_tree(num_vertices(g));
  162. boost::tie(vi, vi_end) = vertices(g);
  163. ++vi;
  164. for (; vi != vi_end; ++vi)
  165. add_edge(parent[*vi], *vi, search_tree);
  166. std::cout << "The breadth-first search tree:" << std::endl;
  167. // Print out the search tree. We use DFS because it visits
  168. // the tree nodes in the order that we want to print out:
  169. // a directory-structure like format.
  170. std::vector<size_type> dfs_distances(num_vertices(g), 0);
  171. print_tree_visitor<NameMap, size_type*>
  172. tree_printer(node_name, &dfs_distances[0]);
  173. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  174. get(vertex_color, g)[*vi] = white_color;
  175. depth_first_visit(search_tree, src, tree_printer, get(vertex_color, g));
  176. return EXIT_SUCCESS;
  177. }