Сортировка EdgeList в boost :: graph - PullRequest
       22

Сортировка EdgeList в boost :: graph

2 голосов
/ 28 сентября 2011

Я хотел бы отсортировать ребро. Список boost :: graph определен следующим образом:

struct Vertex{
int index;
};

struct Edge{
double weight;
};

boost::adjacency_list<boost::listS, boost::listS, boost::undirectedS, Vertex, Edge> Graph;

После добавления вершин и ребер, как отсортировать список ребер.Получаете преимущество с наибольшим весом в первую очередь?

Я знаю, что можно использовать

std::sort(edgeIt_begin,edgeIt_end,compare); 

для векторов, но это не работает для std :: list.

Ответы [ 4 ]

8 голосов
/ 28 сентября 2011

Вы можете написать свой собственный класс EdgeList или OutEdgeList, который автоматически сортирует элементы. Я привожу пример, потому что имхо не так очевидно, как это сделать.

#include <iostream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>

using namespace boost;

template<class T> struct Sorted_list
{
  std::list<T> v;

public:
  typedef T value_type;
  typedef typename std::list<T>::size_type size_type;
  typedef typename std::list<T>::iterator iterator;

  iterator insert(const T& x)
  {
    Sorted_list<T>::iterator i = v.begin();

    while(i != v.end() && x > *i)
    {
      i++;
    }

    return v.insert(i, x);
  }

  iterator begin() { return v.begin(); }
  iterator end() { return v.end(); }

  size_type size() const { return v.size(); }
};

struct SlistS {};

namespace boost {
  template <class ValueType> struct container_gen<SlistS, ValueType>
  {
    typedef Sorted_list<ValueType> type;
  };

  struct sorted_list_tag {};

  template<class T> sorted_list_tag container_category(Sorted_list<T>&)
  {
    return sorted_list_tag();
  }

  template<class T> std::pair<typename Sorted_list<T>::iterator, bool>
  push_dispatch(Sorted_list<T>& v, const T& x, sorted_list_tag)
  {
    return std::make_pair(v.insert(x), true);
  }

  template <> struct parallel_edge_traits<SlistS> { 
    typedef allow_parallel_edge_tag type;
  };
}

int main()
{
  typedef adjacency_list<SlistS> Graph;
  Graph g(10);
  add_edge(1, 2, g);
  add_edge(1, 5, g);
  add_edge(1, 3, g);
  add_edge(1, 7, g);
  add_edge(1, 1, g);

  graph_traits<Graph>::edge_iterator i, end;

  for (tie(i, end) = edges(g); i != end; ++i) {
    std::cout << source(*i, g) << " -> " << target(*i, g) << std::endl;
  }

  return 0;
}

Выход:

1 -> 1
1 -> 2
1 -> 3
1 -> 5
1 -> 7
2 голосов
/ 28 сентября 2011

Сортировка ребер не идиоматическая надстройка :: граф. Посмотрите на реализацию BGL из алгоритма Крускала для остовных деревьев. Алгоритм должен смотреть на каждое ребро в порядке возрастания веса.

  std::priority_queue<Edge, std::vector<Edge>, weight_greater> Q(wl);
  /*push all edge into Q*/
  typename graph_traits<Graph>::edge_iterator ei, eiend;
  for (boost::tie(ei, eiend) = edges(G); ei != eiend; ++ei) 
    Q.push(*ei);

Он использует отдельную структуру данных для сортировки ребер, а затем выполняет итерацию по ребрам в указанном порядке. В вашем случае вы сначала хотите получить максимально взвешенные ребра, поэтому вам нужно изменить оператор сравнения.

0 голосов

Предыдущий ответ, хотя и очень полезный, немного некорректно управляет тегами bgl, что приводит к избыточному определению push_dispatch и может привести к проблемам со сборкой при вызове других функций * _dispatch (например, в случае операций стирания).

Второе сбивающее с толку обстоятельство заключается в том, что список ребер для каждого узла подставляется в шаблоне adj_list, но неповрежденный список целых ребер печатается.

Есть некоторый код, который предположительно исправляет эти недостатки:

// ...

template<class T> struct Sorted_vector : public std::vector<T>
{
public:

  iterator insert(const T& x)
  { 
    iterator where = std::upper_bound(begin(), end(), x, std::less<T>());
    return std::vector<T>::insert(where, x);
  }

};

struct vecSS{};

namespace boost{

    template <class ValueType> struct container_gen<vecSS, ValueType>
    {
        typedef Sorted_vector<ValueType> type;
    };

    template <> struct parallel_edge_traits<vecSS> { 
        typedef allow_parallel_edge_tag type;
    };

    template<class T> graph_detail::vector_tag container_category(const Sorted_vector<T>&)
    {
        return graph_detail::vector_tag();
    }

    template <class T> graph_detail::unstable_tag iterator_stability(const Sorted_vector<T>&)
    {
        return graph_detail::unstable_tag();
    }
}

typedef adjacency_list<vecSS, ...> Graph;

// ....

  graph_traits<Graph>::vertex_iterator ii, ee;
  for(boost::tie(ii,ee) = vertices(g);ii!=ee;++ii){
       std::cout << *ii << std::endl;
       graph_traits<Graph>::adjacency_iterator jj, ff;
       for(boost::tie(jj,ff)=adjacent_vertices(*ii, g);jj != ff; ++jj){
            std::cout << "\t -> " << *jj<<std::endl;
       }
  }
0 голосов
/ 28 сентября 2011

Я не знаю о каких-либо взаимодействиях с представлением Boost Graph, но IIRC вы можете использовать std::list::sort(Cmp)

std::list<int> l = { 1, 3, -1, 9, 2 };
l.sort();
...