1. 程式人生 > >最小生成樹總結(prim、並查集和kruskal) C++實現

最小生成樹總結(prim、並查集和kruskal) C++實現

#ifndef ___00_alg_tests__minimal_spanning_tree__
#define ___00_alg_tests__minimal_spanning_tree__

#include <stdio.h>
#include <string.h>
#include <list>
#include <vector>

#include "union_find.h"

#define _DEBUG_
#ifdef _DEBUG_
#include <iostream>
using namespace std;

#endif

#define MAX_DISTENCE 0xfffffff

// Vertex value
template<class T,class keyType = long>
class Vertex {
public:
    typedef T valueType;
    Vertex(keyType key, T value) : m_key(key), m_value(value) {
        m_dis = MAX_DISTENCE;
        m_known = false;
        m_isVisited = false;
    };
    
    ~Vertex(){};
    int getDis() { return m_dis;};
    void setDis(int dis) { m_dis = dis; return ;};
    bool isknown() { return m_known;};
    keyType getKey() { return m_key;};
    void init() { m_known = false; m_isVisited = false;};
    void setKnown() { m_known = true; return ;};
    bool isVisited() { return m_isVisited;};
    void setVisited() { m_isVisited = true; return ;};
private:
    keyType m_key;          /* 頂點關鍵字. */
    valueType m_value;      /* 頂點值. */
    int m_dis;              /* 距離. */
    bool m_known;           /* 是否已被遍歷(prim演算法). */
    bool m_isVisited;       /* 標識是否被訪問過(DFS演算法). */
};

// Edge
template<class T,class weightType = int>
class Edge {
public:
    typedef T nodeType;
    Edge(T *ori, T *des, weightType weight) : \
    m_ori(ori), m_des(des), m_weight(weight) { };
    ~Edge() { };
    T *getOri() { return m_ori;};
    T *getDes() { return m_des;};
    weightType getWeight() { return m_weight;}
    bool operator< (const Edge<T,weightType> *M) const {
        return m_weight < M->getWeight();
    };
private:
    nodeType *m_ori;            /* 邊的起始點. */
    nodeType *m_des;            /* 邊的終止點. */
    weightType m_weight;        /* 邊的權值. */
};

template<class T, class edgeType>
class VertexNode {
public:
    typedef T nodeType;
    
    VertexNode(T *node) : m_vertex(node) { m_iter = m_adj.begin();};
    ~VertexNode() { };
    
    /* 清除演算法對頂點的副作用. */
    void init() { if (m_vertex){ m_vertex->init(); } return ;};
    
    /* 新增邊到圖. */
    void addEdge(edgeType *edge) { m_adj.push_back(edge);};
    
    /* 獲取頂點的臨接邊. */
    edgeType *getAdj() { m_iter = m_adj.begin();return *m_iter;};
    
    /* 獲取該頂點的下一條臨接邊 .*/
    edgeType *getNext() { m_iter++; return (m_iter != m_adj.end()) ? *m_iter : NULL;};
    
    /* 獲取頂點元素. */
    T *getVertex() { return m_vertex;};
    
    /* 標識此頂點是否被訪問過(prim演算法). */
    bool isKnown() { return (m_vertex) ? m_vertex->isknown() : false;};
    
    /* 設定此頂點已經被訪問過(prim演算法). */
    void setKnown() { if (m_vertex) {m_vertex->setKnown();} return ;};
    
    /* 獲取距離--prim演算法*/
    int getDis() { if (m_vertex) { return m_vertex->getDis();} exit(-1);}
    
    /* 設定距離. */
    void setDis(int dis) { if (m_vertex) { m_vertex->setDis(dis);} return ;};
    
    /* 標識此頂點是否被訪問過(dfs演算法). */
    bool isVisited() { return (m_vertex) ? m_vertex->isVisited() : false ;};
    
    /* 設定此頂點已經被訪問過(dfs演算法). */
    void setVisited() { if (m_vertex) {m_vertex->setVisited();} return ;};
    
private:
    nodeType *m_vertex;                             /* 頂點元素 */
    std::list<edgeType*> m_adj;                     /* 頂點的鄰接表. */
    typename std::list<edgeType*>::iterator m_iter; /* 用於遍歷鄰接點. */
};


template<class T,class edgeType>
class Graph {
public:
    Graph(){};
    ~Graph(){};
    typedef VertexNode<T,edgeType> VertexNodeType;
    
    /* 清除演算法對圖的副作用. */
    void init();
    
    /* Prim演算法. */
    void prim();
    
    /* 深度優先遍歷. */
    void dfs(VertexNodeType* src);
    
    /* 向圖中增加一個頂點. */
    void addNode(VertexNode<T,edgeType> *node) { m_vertexNodeSet.push_back(node);};
    
    void kruskal();
private:
    /* 頂點集. */
    std::list<VertexNodeType*> m_vertexNodeSet;
    
    /* 找到最短的邊集--用於prim演算法 */
    VertexNodeType* findMindis();
    
    void sortEdge(list<edgeType*> &edgeSet);
};

template<class T,class edgeType>
void Graph<T,edgeType>::init() {
    typename std::list<VertexNodeType*>::iterator it;
    for (it = m_vertexNodeSet.begin(); it != m_vertexNodeSet.end(); ++it) {
        it->init();
    }
    return ;
}

template<class T,class edgeType>
VertexNode<T,edgeType>* Graph<T,edgeType>::findMindis() {
    int min = MAX_DISTENCE;
    VertexNodeType* minDisNode = NULL;
    
    // for_each node.
    typename std::list<VertexNodeType*>::iterator iter;
    for (iter = m_vertexNodeSet.begin(); \
         iter != m_vertexNodeSet.end(); ++iter) {
        
        VertexNodeType* tmp = *iter;
        if (tmp->isKnown()) {
            continue;
        }
        if (min > tmp->getDis())
        {
            min = tmp->getDis();
            minDisNode = tmp;
        }
        
    }
    return minDisNode;
}

template<class T,class edgeType>
void Graph<T,edgeType>::prim() {
    VertexNodeType *nodeTmp = m_vertexNodeSet.front();
    if (!nodeTmp) {
        //cout<<"No Node exist in this Graph."<<endl;
        return ;
    }
    nodeTmp->setDis(0);
    nodeTmp->setKnown();
    
#ifdef _DEBUG_
    cout<<"Node's key = "<<nodeTmp->getVertex()->getKey();
    cout<<",Distence = "<<nodeTmp->getVertex()->getDis()<<endl;
#endif
    
    // For_each node.
    for (; ;) {
        edgeType* edgeTmp = nodeTmp->getAdj();
        
        // For_each adj node.
        while (edgeTmp) {
            T * Vtmp = edgeTmp->getDes();
#ifdef _DEBUG_
            cout<<"Node("<<Vtmp->getKey()<<") "<<endl;;
#endif
            if (Vtmp->isknown()) {
                edgeTmp = nodeTmp->getNext();
                continue;
            }
            
            // Update dis.
            if (edgeTmp->getWeight() < Vtmp->getDis()) {
                Vtmp->setDis((int)edgeTmp->getWeight());
            }
            edgeTmp = nodeTmp->getNext();
        }

        // Find the node which has min dis.
        nodeTmp = findMindis();
        if (!nodeTmp) {
            break;
        }
        nodeTmp->setKnown();
#ifdef _DEBUG_
        cout<<"Node's key = "<<nodeTmp->getVertex()->getKey();
        cout<<",Distence = "<<nodeTmp->getVertex()->getDis()<<endl;
#endif

    }
    
    return ;
}

template<class T,class edgeType>
void Graph<T,edgeType>::sortEdge(list<edgeType*> &edgeSet) {
    typename std::list<VertexNodeType*>::iterator it;
    for (it = m_vertexNodeSet.begin(); it != m_vertexNodeSet.end(); ++it) {
        edgeType *edgeTmp = it->getAdj();
        while (edgeTmp) {
            edgeSet->push_back(edgeTmp);
            edgeTmp = it->getNext();
        }
    }
    sort(edgeSet.begin(), edgeSet.end(), less<edgeType>());
    return ;
}

template<class T,class edgeType>
void Graph<T,edgeType>::kruskal() {
    // Init
    list<edgeType*> edgeSet;// 這裡用優先佇列效率更高
    sortEdge(edgeSet);
    list<edgeType*> treeEdgeSet;//最小生成樹邊集
    
    int vertexArraySize = m_vertexNodeSet.size();
    T *vertexArray = (T*)malloc(sizeof(T*)*vertexArraySize);
    typename std::list<VertexNodeType*>::iterator iter;
    int i = 0;
    for (iter = m_vertexNodeSet.begin(); iter != m_vertexNodeSet.end(); ++iter) {
        vertexArray[i] = iter->getVertex();
        i++;
    }
    UnionFind<T*> vertexUnion(vertexArray,vertexArraySize);
    
    typename std::list<edgeType*>::iterator it;
    for (it = edgeSet.begin(); it != edgeSet.end(); ++it) {
        // Find Min dis edge.
        edgeType *edgeMin = it->front();it->pop_front();
        
        // Is the ori node and des node in same set?
        T *ori = edgeMin->getOri();
        T *des = edgeMin->getOri();
        
        // If in same set,Ignore.If not,combain the set and add this edge.
        if (vertexUnion.isConnected(ori, des)) {
            continue;
        } else {
            vertexUnion.unionT(ori, des);
            treeEdgeSet->push_back(edgeMin);
        }
    }
    
#ifdef _DEBUG_
    typename std::list<edgeType*>::iterator itera;
    for (itera = treeEdgeSet.begin(); itera != treeEdgeSet.end(); itera++) {
        cout<<itera->getWeight()<<endl;
    }
#endif
    
    // Free vertexArray.
    if (vertexArray) {
        free(vertexArray);
        vertexArray = NULL;
    }
    
    return ;
}

/* 深度優先遍歷. */
template<class T,class edgeType>
void Graph<T,edgeType>::dfs(VertexNodeType *src) {
    // Set node Visited.
    VertexNodeType *V = src;
    V->setVisited();
    
    // For each W adj to V.
    edgeType *edgeTmp = V->getAdj();
    while (edgeTmp) {
        T *Vtmp = edgeTmp->getDes();
        if (!Vtmp->isKnown()) {
            dfs(Vtmp);
        }
        edgeTmp = V->getNext();
    }
    
    return ;
}

int testGraphPrim();
int testGraphKruskal();

#endif /* defined(___00_alg_tests__minimal_spanning_tree__) */

單元測試程式原始碼: