如何使用STL实现Prim的算法?

时间:2016-11-28 18:23:59

标签: c++ algorithm vector stl unordered-map

我正在尝试实现一个数据结构,它是堆和无序映射的组合。 堆将保存图形节点,包含标识符和成本。 我使用min_extract函数在log(n)时间内让节点接下来展开。 [我正在使用std :: vector和std :: make_heap,pop_heap等算法实现堆]

无序地图保存节点,矢量映射中的位置。无序映射用于支持包含和更新节点功能。但是对于我这样做,我需要节点及其在向量中的位置之间的映射,否则我被迫对该项进行线性搜索。

更令人担心的是,我推动或弹出一个项目,并调用push_heap或pop_heap,这将在向量中的节点周围移动,并且我在地图中保持的位置将最终出错。

那么我该如何实现这个功能,在那里我可以维护节点和它的位置之间的映射。

    void push(T elem) // This will 0(n)... As the element has to be found
    {
        heapVec_.push_back(elem); // add tp vec

        std::push_heap<compar_> (heapVec_.begin() , heapVec_.end());
        // sort ? or just find in the vec ? 
        std::size_t pos = 0 ;

        // find position of the item in the vector
        std::find_if(heapVec_.begin() , heapVec_.end() , [&pos , &elem](const T& item)
                {

                    if(item == elem)
                    {
                        return true;
                    }
                    else
                    {
                        ++pos;
                    }
                });


        // add to map
        heapMap_.emplace_back(elem , pos); // how to keep track of the element where this object is added to ? 

    }   

我正在寻找的数据结构必须支持: 找到最小值:O(lg n) 包含:O(1) 更新节点:O(lg n) insert:O(lg n)

如果我推出自己的堆,当我向上或向下执行冒泡时,我将更新地图中节点的位置,这将是微不足道的。在我这样做之前,我想确保在STL中无法做到这一点。

2 个答案:

答案 0 :(得分:0)

如果将 edge 放入优先级队列而不是节点,那么您不需要更新节点功能,一切都变得容易了。

  • 使用某种集合实现来跟踪树中的顶点。
  • 使用优先级队列来维护可能边缘的有序队列。

然后:

  1. 将初始顶点添加到集合中,并将其边缘添加到优先级队列

  2. 从优先级队列中删除最便宜的边缘。

  3. 如果E的顶点V之一不在树中,则将E和V添加到树中。 V进入您的设置。如果V对于不在集合中的节点有任何边缘,则将这些边缘添加到优先级队列。

  4. 返回第2步,直到队列为空。

答案 1 :(得分:0)

这个想法是从一个空的堆开始,并在进行过程中将顶点推入其中。我们可以多次将相同的顶点推入堆中,但是我们仍然可以正确地形成MST(使用父列表),并且总体复杂度仍然为O(E * log(V))。这样,我们不必实现decrease_key函数。

一个人可以使用priority_queue来实现。 但是,我使用push_heappop_heap函数来实现它:

#include <iostream>
#include <vector>
#include<algorithm>
#include<climits>
using namespace std;
void addEdge(vector<vector <pair<int, int> > >&adj, int u, int v, int w) 
{ 
    adj[u].push_back(make_pair(v, w)); 
    adj[v].push_back(make_pair(u, w)); 
}

int main(){
  vector<vector <pair<int, int> > >adj(9); // Taking a 9 node graph for testing.
  addEdge(adj, 0, 1, 4); 
  addEdge(adj, 0, 7, 8); 
  addEdge(adj, 1, 2, 8); 
  addEdge(adj, 1, 7, 11); 
  addEdge(adj, 2, 3, 7); 
  addEdge(adj, 2, 8, 2); 
  addEdge(adj, 2, 5, 4); 
  addEdge(adj, 3, 4, 9); 
  addEdge(adj, 3, 5, 14); 
  addEdge(adj, 4, 5, 10); 
  addEdge(adj, 5, 6, 2); 
  addEdge(adj, 6, 7, 1); 
  addEdge(adj, 6, 8, 6); 
  addEdge(adj, 7, 8, 7);

  vector<int> key(9, INT_MAX);
  vector<int> parent(9, -1);
  vector<bool> isInMST(9, false);

  key[0] = 0; // Source node is 0, its key value is also 0.
  vector<pair<int, int> > heap; // Vector named as heap.
  heap.push_back(make_pair(0, 0)); // No need to call make_heap as it has only 1 element.

  while(!heap.empty()){
    pair<int, int> temp = heap.front();
    pop_heap(heap.begin(), heap.end(), [ ] (pair<int, int> l, pair<int, int> r){
      return l.first > r.first;
    });
    heap.pop_back();
    int u = temp.second;
    isInMST[u] = true;
    for(int i=0; i<adj[u].size(); i++){
      int v = adj[u][i].first;
      int w = adj[u][i].second;
      if(!isInMST[v] && key[v] > w){
        key[v] = w;
        heap.push_back(make_pair(w, v));
        push_heap(heap.begin(), heap.end(), [ ] (pair<int, int> l, pair<int, int> r){
          return l.first > r.first;
        });
        parent[v] = u;
      }
    }
  }

  for (int i = 1; i < 9; i++) // Starting from 1, as 0 is source.
    cout << parent[i] << " - " << i << endl; // Print edges of MST using parent array.

  return 0;
}