1. 程式人生 > >(c++)資料結構與演算法之圖:鄰接矩陣、深度廣度遍歷、構造最小生成樹(prim、kruskal演算法)

(c++)資料結構與演算法之圖:鄰接矩陣、深度廣度遍歷、構造最小生成樹(prim、kruskal演算法)

//圖的鄰接矩陣實現
//廣度遍歷bfs和深度遍歷dfs
//構造最小生成樹的prim、kruskal演算法

#include <iostream>
#include<stack>
#include<queue>
#define WEIGHTMAX  100
#define VERTEXMAX 50
#define VISITED 1
#define UNVISITED 0
using namespace std;
class ufset             //等價類
{
private:
    int n;                      //個數
    int *root,*next,*length;    //等價類代表元、下一個元素、該元素所在等價類的元素個數
public:
    friend class graph;
    ufset(int s)                //初始時均各自為等價類
    {
        root=new int[s];
        next=new int[s];
        length=new int[s];
        n=s;
        for(int i=0;i<s;i++)
        {
            root[i]=next[i]=i;
            length[i]=1;
        }
    }
    ~ufset()
    {
        delete [] root;
        delete [] next;
        delete [] length;
    }
    void show()                 //輸出
    {
        cout<<"root:"<<endl;
        for(int i=0;i<n;i++)
        {
            cout<<root[i]<<" ";
        }
        cout<<endl;
        cout<<"next:"<<endl;
        for(int i=0;i<n;i++)
        {
            cout<<next[i]<<" ";
        }
        cout<<endl;
        cout<<"length:"<<endl;
        for(int i=0;i<n;i++)
        {
            cout<<length[i]<<" ";
        }
        cout<<endl;
    }
    void Union(int u,int v)         //兩個等價類的合併
    {
        if(length[root[u]]<length[root[v]])
        {
            int temp=u;
            u=v;
            v=temp;
        }
        if(root[u]==root[v])    return;
        int p=next[root[u]];        //next
        next[root[u]]=next[root[v]];
        next[root[v]]=p;
        length[root[v]]=1;                //length
        length[root[u]]++;
        int oldroot=root[v];        //root
        for(int i=0;i<n;i++)
            if(root[i]==oldroot)
                root[i]=root[u];
    }
    bool unionOK(int u,int v)   //兩個元素是否在同一個等價類中
    {
        if(root[v]==root[u])
            return true;
        else
            return false;
    }
};
class edge              //邊類(資料公開)
{
public:
    int start,end;
    int weight;
    friend class graph;
    edge(){};
    edge(int w)
    {
        weight=w;
    }
    edge(int s,int e,int w)
    {
        start=s;
        end=e;
        weight=w;
    }

};
void visit(int v)
{
    cout<<v<<"-->";
}
class graph
{
private:
    int **matrix;           //鄰接矩陣
    int v_num,e_num;        //結點數、邊數
    int *mark;              //用於判斷是否被訪問的陣列(0:未訪問  1:已訪問 )
public:
    graph(){};
    graph(int v)
    {
        if(v>=VERTEXMAX)    cout<<"construct false"<<endl;
        v_num=v;
        e_num=0;
        mark=new int[v_num];
        for(int i=0;i<v_num;i++)
            mark[i]=0;
        matrix=new int*[v_num];
        int i,j;
        for(i=0;i<v_num;i++)
            matrix[i]=new int[v_num];
        for(i=0;i<v_num;i++)
            for(j=0;j<v_num;j++)
                matrix[i][j]=0;
    }
    ~graph()
    {
        delete mark;
        for(int i=0;i<v_num;i++)    delete [] matrix[i];
        delete [] matrix;
    }
    void resetMark()                    //重置節點標記陣列
    {
        for(int i=0;i<v_num;i++)
            mark[i]=0;
    }
    bool isEdge(edge onee)              //判斷是否為邊
    {
        if(matrix[onee.start][onee.end]>0&&
           matrix[onee.start][onee.end]<WEIGHTMAX&&
           matrix[onee.end][onee.start]>0&&
           matrix[onee.end][onee.start]<WEIGHTMAX)
            return true;
        else        return false;
    }
    void setEdge(int start,int end,int weight)      //給圖新增一條邊
    {
        if(matrix[start][end]==0&&matrix[end][start]==0)
        {
            e_num++;
        }
        matrix[start][end]=weight;
        matrix[end][start]=weight;
    }
    void delEdge(int start,int end)                 //刪除圖中一條邊
    {
        if(matrix[start][end]!=0&&matrix[end][start]!=0)
            e_num--;
        else    return;
        matrix[start][end]=0;
        matrix[end][start]=0;
    }
    void showEdge()                     //展示鄰接矩陣
    {
        cout<<"鄰接矩陣如下: "<<endl;
        for(int i=0;i<v_num;i++)
            for(int j=0;j<v_num;j++)
            {
                cout<<matrix[i][j]<<" ";
                if(j==v_num-1)      cout<<endl;
            }
    }
    edge firstEdge(int v)               //返回該結點按順序的第一條邊
    {
        edge e(v,v,0);
        for(int i=0;i<v_num;i++)
        {
            if(matrix[v][i]!=0)
            {
                e.end=i;
                e.weight=matrix[v][i];
                return e;
            }

        }
        cout<<"this vertex dont have edge"<<endl;
        return e;
    }
    edge nextEdge(int v,edge onee)      //返回該邊的下一條邊(同頭結點)
    {
        for(int i=onee.end+1;i<v_num;i++)
        {
            if(matrix[v][i]!=0)
            {
                edge e(v,i,matrix[v][i]);
                return e;
            }
        }
        cout<<"no next edge"<<endl;
        return onee;
    }
    void dfs_traverse(graph g,int fir)  //遞迴深度遍歷
    {
        mark[fir]=1;
        cout<<fir<<"-->";
        for(int i=0;i<v_num;i++)
        {
            if(g.matrix[fir][i]>=1&&!mark[i])
                dfs_traverse(g,i);
        }
    }
    void dfs_notraverse()               //非遞迴深度遍歷(用棧實現)
    {
        resetMark();
        stack<int> s;
        for(int i=0;i<v_num;i++)
        {
            if(mark[i]==0)
            {
                s.push(i);
                while(!s.empty())
                {
                    int pc=s.top();
                    s.pop();
                    if(mark[pc]==0)
                        visit(pc);
                    mark[pc]=1;
                    for(int j=v_num-1;j>0;j--)
                    //for(int j=0;j<v_num;j++)              //???   為何順序顛倒???
                    {
                        if(matrix[pc][j]>0&&matrix[pc][j]<WEIGHTMAX)
                        if(mark[j]==0)
                            s.push(j);
                    }
                }
            }
        }
    }
    void bfs()                          //廣度遍歷(用佇列實現)
    {
        resetMark();
        queue<int> q;
        for(int i=0;i<v_num;i++)
        {
            if(mark[i]==0)
            {
                q.push(i);
                while(!q.empty())
                {
                    int pc=q.front();
                    q.pop();
                    if(mark[pc]==0)
                        visit(pc);
                    mark[pc]=1;
                    for(int j=0;j<v_num;j++)
                    //for(int j=v_num;j>=0;j--)                 //?????
                    {
                        if(matrix[pc][j]>0&&matrix[pc][j]<WEIGHTMAX)
                            if(mark[j]==0)
                                q.push(j);
                    }

                }
            }
        }
    }
    void prim()                         //prim
    {
        resetMark();
        int x=0,y=0;                            //下標
        edge *e=new edge[v_num-1];              //構建的最小生成樹的邊組成的陣列
        int *ver=new int[v_num];                //結點的陣列,用於統計哪些結點已被構建,當陣列滿時說明構建完成
        {//初始化markedge
            for(int i=0;i<v_num;i++)
                ver[i]=-1;
        }
        ver[0]=0;                               //放入首個結點
        mark[0]=1;
        y++;
        while(y<v_num)                          //如果結點沒有全部訪問完則迴圈
        {
            int minWeight=WEIGHTMAX,sta,en;
            for(int i=0;ver[i]!=-1;i++)         //遍歷尋找權重最小的邊
            {
                for(int j=0;j<v_num;j++)
                {
                    //如果邊滿足:權重最小、邊的尾結點未被訪問,則加入邊的尾結點
                    if(matrix[ver[i]][j]!=0&&minWeight>matrix[ver[i]][j]
                       &&mark[j]==0)
                    {
                        minWeight=matrix[ver[i]][j];
                        sta=ver[i];
                        en=j;
                    }
                }
            }
            edge temp(sta,en,minWeight);
            e[x++]=temp;
            ver[y++]=en;
            mark[en]=1;
        }
        {//展示結果:
            cout<<"插入邊順序: "<<endl;
            for(int i=0;i<v_num-1;i++)
                cout<<e[i].start<<"---"<<e[i].weight<<"--->"<<e[i].end<<endl;
            cout<<"插入結點順序: ";
            for(int i=0;i<v_num;i++)
                cout<<ver[i]<<"  ";
            cout<<endl;
        }
        delete [] ver;
        delete [] e;
    }
    void kruskal()                      //kruskal
    {
        int n=v_num,union_num=0;
        queue<edge> q;
        ufset ufs(n);
        {//遍歷使所有邊按權重從小到大的順序排成陣列,進隊
            edge eq[e_num];
            int x=0;
            int **edgew=new int*[n];
            edgew=matrix;
            while(x<+e_num)
            {
                for(int i=0;i<n;i++)
                {
                    for(int j=0;j<n;j++)
                    {
                        if(edgew[i][j]!=0)
                        {
                            edge e(i,j,edgew[i][j]);
                            eq[x++]=e;
                            edgew[i][j]=edgew[j][i]=0;
                        }
                    }
                }
            }
            for(int i=0;i<e_num;i++)
            {
                int minweight=eq[i].weight;
                for(int j=0;j<e_num;j++)
                    {
                        if(eq[j].weight>minweight)
                        {
                            minweight=eq[j].weight;
                            edge temp;
                            temp=eq[j];
                            eq[j]=eq[i];
                            eq[i]=temp;
                        }
                    }
            }
            for(int i=0;i<e_num;i++)
                q.push(eq[i]);
            delete edgew;
        }
        cout<<"邊插入順序:"<<endl;
        while(!q.empty())
        {
            edge e=q.front();
            q.pop();
            if(!ufs.unionOK(e.start,e.end))
            {
                cout<<e.start<<"---"<<e.weight<<"--->"<<e.end<<endl;
                ufs.Union(e.start,e.end);
            }
        }
        cout<<"結點插入順序:";
        for(int i=0;i<n;i++)
        {
            cout<<ufs.next[i]<<"  ";
        }
        cout<<endl;
    }

};
int main()
{
    graph a(8);
    {//set edge(初始化圖)
        a.setEdge(0,1,1);
        a.setEdge(0,2,2);
        a.setEdge(1,3,3);
        a.setEdge(1,4,5);
        a.setEdge(3,7,4);
        a.setEdge(4,7,4);
        a.setEdge(2,6,1);
        a.setEdge(2,5,3);
        a.setEdge(5,6,2);
    }
    cout<<"帶權無向圖:(P160 4-12)"<<endl;
    a.showEdge();
    cout<<" node1 first edge's weight: "<<a.firstEdge(1).weight<<endl;
    cout<<"node2 first edge's next edge's weight: "<<a.nextEdge(2,a.firstEdge(2)).weight<<endl;
    cout<<"遞迴深度遍歷:   ";
    a.dfs_traverse(a,0);
    cout<<endl;
    cout<<"非遞迴深度遍歷:  ";
    a.dfs_notraverse();
    cout<<endl;
    cout<<"    廣度遍歷:  ";
    a.bfs();
    cout<<endl;
    cout<<"prim:"<<endl;
    a.prim();
    cout<<"kruskal:"<<endl;
    a.kruskal();

    cout << "Hello world!" << endl;
    return 0;
}
第一次寫,寫的比較複雜,將就看吧。