草庐IT

c++ - Prim 的最小生成树

coder 2024-02-05 原文

我正在尝试使用 Prim 的最小生成树算法优化图形。但我没有得到想要的答案。

算法:

1. Construct min heap array. The array consists of nodes which have a vertex value 
and a key value. The key values are initialized to INT_MAX initially.

2. Make the zeroth node's key 0, as this is the starting node.

3. I iterate over the heap, till it becomes empty, and in every step following is done:
     - Extract the minimum element out of the min heap. This is done by extractMin()
       function in the class MinHeap. 

4. Look for this extracted element's neighbors and update their keys based on the weight of 
the corresponding edge.

5. Then decrease the key value in the minHeap by using decreaseKey() function in 
class MinHeap.

6. Store the parent and child for which the condition satisfies in a map called parent.

这是代码说明:

1. The code contains two header files, Graph.h and MinHeap.h. The functions are all std f
functions in these files. So there won't be any problem in understanding them.

2. The Graph.cpp file contains the PrimMST() function which does all the job and performs 
the entire algorithm.

问题是:

1. When I extract a node from heap in PrimMST() function, I call extractMin() function 
defined in MinHeap.cpp file. This function swaps the top most node in the heap with the 
bottom most node. And then performs the heapify operation.


But, it is not performing this operation though I have called it in extractMin(). There's
no problem with minHeapify function which does the heapify operation as it does 
perform its job else where is the program.

这是我要优化的图表:

这是程序: P.S.:我发布了包含所有头文件的完整代码,以便于理解。但跳过代码,请观察Graph.cpp文件中的PrimMST()函数。

/***************GRAPH.H*******************************/

#ifndef GRAPH_H_
#define GRAPH_H_
#include <list>
#include <map>

using namespace std;

class AdjListNode{
    int v;
    int weight;
public:
    AdjListNode(int _v, int _w){ v = _v; weight = _w; }
    int getV()      { return v;  }
    int getWeight() { return weight;  }
};

class Graph{
    int V;                          // To store number of vertices in the graph
    list<AdjListNode> *adj; // This is a map for storing the adjacency list
    map<int,int> mapping;           // A map to form a dictionary of vertex values to their array indexes for look ups.
    map<int,int> parent;            // A map to store the parent child for a given edge in the graph
public:
    Graph(int);                     // Class constructor
    void HashTable(int *, int);     // This method uses the map library in STL to create a mappinh
                                    // of arbitrary integers to zero based array indexes
    int getHashedElt(int);          // This method returns the value corresponding to a given 
                                    // key in a hash table
    void addEdge(int, int, int);    // This method adds the second arg to the adj list of first arg.
    void printGraph();              // This method prints the adjacency list of all the vertices

    void PrimMST(int *, int);       // This function will perform the Prim's MST algorithm and optimize 
                                    // the number of nodes in the graph

};
#endif

/****************GRAPH.CPP*************************/
#include <iostream>
#include <climits>
#include <list>
#include <map>
#include "Graph.h"
#include "MinHeap.h"

#define INF 9999

using namespace std;

Graph::Graph(int v){
    V = v;
    adj = new list<AdjListNode>[V];
}

 // This function takes in a pointer to array and its size as its arguments to create a hashtable.
// So. if you have 10,11,12,13,14,15 as the nodes.
// Create an array int arr[] {10,11,12,13,14,15}, and int size = sizeof(arr)/sizeof(arr[0])
// And pass it to this function this creates a dictionary named mapping for O(1) look up of 
// index by other functions.
void Graph::HashTable(int *nodeData, int size){
    for (int i = 0; i < size; i++){
            mapping[nodeData[i]] = i;
    }
    return;
}


// This method returns the value corresponding to a particular node in constant time.
int Graph::getHashedElt(int data){
    return mapping[data];
}

// This function creates an adjacency list for every vertex in the graph
void Graph::addEdge(int node1, int node2, int weight){
    AdjListNode node(node2, weight);
    int index = getHashedElt(node1);
    adj[index].push_back(node);
}


void Graph::printGraph(){
    list<AdjListNode>::iterator j;
    int i = 0;
    while (i<V){
            for (j = adj[i].begin(); j != adj[i].end(); j++){
                    cout <<"(" << j->getV() << "," << j->getWeight() << ")->";
            }
            if (!adj[i].empty())
                    cout << "NULL\n";
            i++;
    }
}

void Graph::PrimMST(int *arr, int size){
    MinHeap minHeap(arr,size);
    size_t key[V];  // Key values to pick minimum weight edge in cut

    for (int i = 1; i < V; i++){
            parent[arr[i]] = -1;    // All the parents are -1 initially
            key[i] = INT_MAX;       // Initially all the keys are initialised to positive infinity
            MinHeapNode *newNode = minHeap.newMinHeapNode(arr[i],key[i]);
            //cout << "("<< arr[i] << ", " << key[i] << ")\n";
            minHeap.insertNode(i, newNode);
    }

    // Make key value of 0th vertex as 0 so that it is extracted first.
    key[0] = 0;

    // This function insertNode creates a newNode with vertex number and associated key value.
    MinHeapNode *newNode = minHeap.newMinHeapNode(arr[0],key[0]);
    minHeap.insertNode(0, newNode);

    //minHeap.printHeap();  

 while (!minHeap.isEmpty()){
            // Extract the vertex with minimum key value
            minHeap.printHeap();
            MinHeapNode *minNode = minHeap.extractMin();
            // Get the vertex of this minNode.
            int u = minNode->v;
            cout << "\n";
            minHeap.printHeap();
            cout << "\n\n\n";
            //cout << u << "\n";
            // Traverse through all the adjacent vertices of u (extended vertex)
            // and update their key values
            list<AdjListNode>::iterator j;
            for (j = adj[mapping[u]].begin(); j != adj[mapping[u]].end(); j++)  {
                    int v = j->getV();
                    // If v is not yet included in the MST and weight of u-v
                    // is less than key value of v, then update key value
                    // and parent of v
                    if (minHeap.isInMinHeap(v) && j->getWeight() < key[mapping[v]]){
                            key[mapping[v]] = j->getWeight();
    //                      cout << key[mapping[v]] << "\n";
                            parent[v] = u;
                            minHeap.decreaseKey(v,key[mapping[v]]);
                    }
            }
    }
    for (int k = 1; k < size; k++){
            //cout <<parent[arr[k]]<<"---"<<arr[k]<< "\n";
    }
    return;
}


/*************MINHEAP.H**************************/
#ifndef MINHEAP_H_
#define MINHEAP_H_
#include <map>

using namespace std;

struct MinHeapNode{
    int v;
    size_t key;
};

class MinHeap{
    int size;               // Number of heap nodes present in the heap at any given time
    int capacity;           // Capacity of min heap
    map<int,int> pos;       // This is map which stores the array index of a given vertex, for O(1) look up
    MinHeapNode **MinHeapArray;     // This array containe pointers to all the heap nodes.

public:
    MinHeap(int*,int);      // Class constructor, it will allocate space to minHeap and initialise all the variables.
                            // It also creates the map of every vertex to an index, so that there is O(1) look up.
    MinHeapNode *newMinHeapNode(int,size_t);   // This function creates a new min heap node with a given value of vertex and weight
    int getIndex(int);                      // This function returns the index of a given vertex in pos map.
    void insertNode(int,MinHeapNode *);             // This function inserts a node into the MinHeapArray.
    void printHeap();
    void swapMinHeapNode(MinHeapNode **, MinHeapNode **); // It will perform swap operation in the heap.
    void minHeapify(int);      // Standard function to heapify at given idx.
    bool isEmpty();         // A utility function to check whether given heap is empty or not.
    bool isInMinHeap(int);  // Checks whether given vertex in the heap or not
    MinHeapNode *extractMin();      // Std func to extract to minimum node from the heap.
    void decreaseKey(int,int);      // This func performs the decreaseKey op by making use of pos map.

};

#endif


/***************MINHEAP.CPP***************************/
#include <iostream>
#include <cstdlib>
#include <climits>
#include <map>
#include "MinHeap.h"

using namespace std;

MinHeap::MinHeap(int *arr,int s){
    size = 0;
    capacity = s;
    MinHeapArray = (MinHeapNode **)malloc(sizeof(MinHeapNode *)*s);
    for (int i = 0; i < s; i++){
            pos[arr[i]] = i;        // This is a mapping from vertex to array index i. This will enable O(1) access of any var in heap.
    }
}

MinHeapNode *MinHeap::newMinHeapNode(int v, size_t key){
    MinHeapNode *node = new MinHeapNode;
    node->v = v;
    node->key = key;
    return node;
}

int MinHeap::getIndex(int v){
    return pos[v];
}

void MinHeap::insertNode(int idx, MinHeapNode *node){
    MinHeapArray[idx] = node;
    size++;
}

bool MinHeap::isEmpty(){
    return size == 0;
}

bool MinHeap::isInMinHeap(int v){
    if (pos[v] < size)
            return true;
    return false;
}


void MinHeap::printHeap(){
    for (int i = 0; i < size; i++){
            cout << MinHeapArray[i]->v << ", "<< MinHeapArray[i]->key << "\n";
    }
}

void MinHeap::swapMinHeapNode(MinHeapNode **a, MinHeapNode **b){
    MinHeapNode *t = *a;
    *a = *b;
    *b = t;
}

// A standard function to heapify at given index idx
// This function also updates position of nodes when they are swapped.
void MinHeap::minHeapify(int idx){
    int smallest, left, right;
    left = (2*idx + 1);
    right = (2*idx + 2);
    smallest = idx;

    if (left < size && MinHeapArray[left]->key < MinHeapArray[smallest]->key)
            smallest = left;
    if (right < size && MinHeapArray[right]->key < MinHeapArray[smallest]->key)
            smallest = right;
    if (smallest != idx){
            // To nodes to be swapped in min heap
            MinHeapNode *smallestNode = MinHeapArray[smallest];
            MinHeapNode *idxNode = MinHeapArray[idx];

            // Change the mapping of vertices in pos map.
            pos[smallestNode->v] = idx;
            pos[idxNode->v] = smallest;

            // Swap Nodes using swapMinHeapNode utility function
            MinHeap::swapMinHeapNode(&smallestNode, &idxNode);
            minHeapify(smallest);
    }
    return;
}

 MinHeapNode *MinHeap::extractMin(){
    if (isEmpty())
            return NULL;

    // Store the root node
    MinHeapNode *root = MinHeapArray[0];

    // Replace the root with last node
    MinHeapNode *lastNode = MinHeapArray[size-1];
    MinHeapArray[0] = lastNode;

    // Update position of last node
    pos[root->v] = size - 1;
    pos[lastNode->v] = 0;

    // Reduce heap size and heapify root
    size--;
    MinHeap::minHeapify(0);

    return root;
}

void MinHeap::decreaseKey(int v, int key){
    // Get the index of v in heap array
    int i = pos[v];

    // Get the node and update its key value
    MinHeapArray[i]->key = key;

    // Travel up till the complete tree is not heapified.
    // This is O(logn) loop
    while (i && MinHeapArray[i]->key < MinHeapArray[(i-1)/2]->key){
            // Swap this node with its parent

            // First update the pos matrix
            pos[MinHeapArray[i]->v] = (i-1)/2;
            pos[MinHeapArray[(i-1)/2]->v] = i;

            // Do the swapping now.
            MinHeap::swapMinHeapNode(&MinHeapArray[i], &MinHeapArray[(i-1)/2]);

            // move to the parent index in the next iteration
            i = (i - 1)/2;
    }
    return;
}



/**********************MAIN FUNCTION CALL***************/
#include <iostream>
#include "Graph.h"
#include "MinHeap.h"

using namespace std;

int main(){
    int arr[] = {0,1,2,3,4,5,6,7,8};        // An array with all the vertices
    int size = sizeof(arr)/sizeof(arr[0]);

    Graph g(size);
    g.HashTable(arr,size);
    g.addEdge(0, 1, 4);
    g.addEdge(0, 7, 8);
    g.addEdge(1, 2, 8);
    g.addEdge(1, 7, 11);
    g.addEdge(2, 3, 7);
    g.addEdge(2, 8, 2);
    g.addEdge(2, 5, 4);
    g.addEdge(3, 4, 9);
    g.addEdge(3, 5, 14);
    g.addEdge(4, 5, 10);
    g.addEdge(5, 6, 2);
    g.addEdge(6, 7, 1);
    g.addEdge(6, 8, 6);
    g.addEdge(7, 8, 7);
    //g.printGraph();
    g.PrimMST(arr,size);
    return 0;
}

有了这个输入,我得到了错误的输出。请注意,此输出是通过在调用 extractMin() 之前和之后调用 printHeap 获得的。并且可以看出,即使每次提取节点时在 extractMin() 中调用 minHeapify(0)。它以某种方式不执行该操作,因此堆未堆化,导致错误结果 示例输出,前 3 次迭代:

First Iteration:

0, 0
1, 2147483647
2, 2147483647
3, 2147483647
4, 2147483647
5, 2147483647
6, 2147483647
7, 2147483647
8, 2147483647

8, 2147483647
1, 2147483647
2, 2147483647
3, 2147483647
4, 2147483647
5, 2147483647
6, 2147483647
7, 214748364


Second Iteration:
1, 4
7, 8
2, 2147483647
8, 2147483647
4, 2147483647
5, 2147483647
6, 2147483647
3, 2147483647

3, 2147483647
7, 8
2, 2147483647
8, 2147483647
4, 2147483647
5, 2147483647
6, 2147483647 

Third Iteration:
2, 8
7, 8
3, 2147483647
8, 2147483647
4, 2147483647
5, 2147483647
6, 2147483647

6, 2147483647
7, 8
3, 2147483647
8, 2147483647
4, 2147483647
5, 2147483647

请观察第二次和第三次迭代,它们根本没有堆化,即使我最后在 extractMin() 函数中调用了 minHeapify 函数。

我迫切需要这方面的帮助。

最佳答案

你的问题是在这一行 MinHeap::swapMinHeapNode(&smallestNode, &idxNode);minHeapify(int idx) 中,你正在交换指向不存在的节点的指针要交换 MinHeapArray 中的值,您应该交换数组元素,所以这一行应该替换为 MinHeap::swapMinHeapNode(&MinHeapArray[idx], &MinHeapArray[smallest]);

关于c++ - Prim 的最小生成树,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34645620/

有关c++ - Prim 的最小生成树的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  3. ruby - 获取数组中的值并最小化某个类属性的最优雅的方法是什么? - 2

    假设我有以下类(class):classPersondefinitialize(name,age)@name=name@age=ageenddefget_agereturn@ageendend我有一组Person对象。是否有一种简洁的、类似于Ruby的方法来获取最小(或最大)年龄的人?如何根据它对它们进行排序? 最佳答案 这样做会:people_array.min_by(&:get_age)people_array.max_by(&:get_age)people_array.sort_by(&:get_age)

  4. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  5. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  6. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  7. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  8. ruby - Ruby 中字符串运算符 + 和 << 的区别 - 2

    我是Ruby和这个网站的新手。下面两个函数是不同的,一个在函数外修改变量,一个不修改。defm1(x)x我想确保我理解正确-当调用m1时,对str的引用被复制并传递给将其视为x的函数。运算符当调用m2时,对str的引用被复制并传递给将其视为x的函数。运算符+创建一个新字符串,赋值x=x+"4"只是将x重定向到新字符串,而原始str变量保持不变。对吧?谢谢 最佳答案 String#+::str+other_str→new_strConcatenation—ReturnsanewStringcontainingother_strconc

  9. ruby - rails 3.2.2(或 3.2.1)+ Postgresql 9.1.3 + Ubuntu 11.10 连接错误 - 2

    我正在使用PostgreSQL9.1.3(x86_64-pc-linux-gnu上的PostgreSQL9.1.3,由gcc-4.6.real(Ubuntu/Linaro4.6.1-9ubuntu3)4.6.1,64位编译)和在ubuntu11.10上运行3.2.2或3.2.1。现在,我可以使用以下命令连接PostgreSQLsupostgres输入密码我可以看到postgres=#我将以下详细信息放在我的config/database.yml中并执行“railsdb”,它工作正常。开发:adapter:postgresqlencoding:utf8reconnect:falsedat

  10. ruby - 在 Ruby + Chef 中检查现有目录失败 - 2

    这是我在ChefRecipe中的一blockRuby:#ifdatadirdoesn'texist,moveoverthedefaultoneif!File.exist?("/vol/postgres/data")execute"mv/var/lib/postgresql/9.1/main/vol/postgres/data"end结果是:Executingmv/var/lib/postgresql/9.1/main/vol/postgres/datamv:inter-devicemovefailed:`/var/lib/postgresql/9.1/main'to`/vol/post

随机推荐