欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

图-邻接矩阵

程序员文章站 2022-05-20 20:23:48
...

这是一篇关于无向带权图的模板代码整理,用邻接矩阵表示图,实现图的深度优先遍历和广度优先遍历。

也可以改为有向带权图,需要在插入、删除函数作出相应的改变。

邻接矩阵表示图优缺点总结:稠密图用邻接矩阵。

  • 邻接矩阵把所有结点的信息都保留下来,信息保留全面,查询也方便;但,当图中结点的之间联系较少时,这时的邻接矩阵为稀疏矩阵,存储了大量的0或无穷值。信息价值密度低。只有稠密图对应的邻接矩阵才不是稀疏矩阵,因此,复杂的图用邻接矩阵表示为佳。

 

//
//  main.cpp
//  图-邻接矩阵
//
//  Created by scnulpc on 2018/10/22.
//  Copyright © 2018年 scnulpc. All rights reserved.
//

#include <iostream>
#include <queue>
#define maxWeight 99
using namespace std;
const int DefaultVertices = 30;

template <class T,class E>
class Graph     //带权无向图
{
private:
    T * VerticesList;   //顶点表
    E **Edge;           //邻接矩阵
    int maxVertices;    //图中最大顶点数
    int numEdges;       //当前边数
    int numVertices;    //当前顶点数
    
    
public:
    Graph(int sz=DefaultVertices);
    ~Graph();
    int numberOfVertices(){return numVertices;}
    int numberOfEdge(){return numEdges;}
    int getVertexPosition(T v);         //获取顶点v的位置
    T getValue(int i);                  //取顶点i的值,i不合理返回0
    E getWeight(int v1,int v2);         //取边(v1,v2)边上的权值
    int getFirstNeighbor(int v);        //取顶点v的第一个邻接顶点
    int getNextNeighbor(int v,int w);   //取v的邻接顶点w的下一个邻接顶点
    bool insertVertex(const T& vertex); //插入顶点vertex
    bool insertEdge(int v1,int v2,E weight);//插入边
    bool removeVertex(int v);           //删除顶点v及其关联的边
    bool removeEdge(int v1,int v2);     //删除边(v1,v2)
    friend istream& operator>>(istream& in,Graph<T,E> &g);//重载输入
    friend ostream& operator<<(ostream& out,Graph<T,E> &g);//重载输出
    void input();   //测试输入
    void output();  //测试输出
    void outputAsMatrix();  //测试输出
};

template <class T,class E>
Graph<T, E>::Graph(int sz)
{
    VerticesList = new T[sz];
    maxVertices=sz;
    numVertices=0;
    numEdges=0;
    Edge = new E* [sz];
    for (int i=0; i<maxVertices; i++)
    {
        Edge[i] = new E[sz];
    }
    for (int i=0; i<maxVertices; i++)
    {
        for (int j=0; j<maxVertices; j++)
        {
            if (i==j) Edge[i][j]=0;
            else Edge[i][j] = maxWeight;
        }
    }
}
template <class T,class E>
Graph<T, E>::~Graph<T, E>()
{
    delete []VerticesList;
    delete []Edge;
}
template <class T,class E>
int Graph<T,E>::getVertexPosition(T v)
{
    for (int i=0; i<numVertices; i++) {
        if (VerticesList[i]==v)return i;
    }
    return -1;
}
template <class T,class E>
T Graph<T,E>::getValue(int i)
{
    return (i>=0&&i<numVertices)? VerticesList[i]:0;
}
template <class T,class E>
E Graph<T,E>::getWeight(int v1, int v2)
{
    return (v1!=-1&&v2!=-1)? Edge[v1][v2]:0;
}
template <class T,class E>
int  Graph<T,E>::getFirstNeighbor(int v)
{
    if (v!=-1) {
        for (int i=0; i<numVertices; i++) {
            if (Edge[v][i]>0&&Edge[v][i]<maxWeight) return i;
        }
    }
    return -1;
}
template <class T,class E>
int  Graph<T,E>::getNextNeighbor(int v, int w)
{
    if (v!=-1&&w!=-1) {
        for (int column = w+1; column<numVertices; column++) {
            if (Edge[v][column]>0&&Edge[v][column]<maxWeight) return column;
        }
    }
    return -1;
}

template <class T,class E>
bool Graph<T,E>::insertVertex(const T &vertex)
{
    if (numVertices==maxVertices) return false;
    VerticesList[numVertices++]=vertex;
    return true;
}
template <class T,class E>
bool  Graph<T,E>::insertEdge(int v1, int v2, E weight)
{
    if (v1!=-1&&v2!=-1) {
        Edge[v1][v2]=Edge[v2][v1]=weight;
        return true;
    }
    return false;
}
template <class T,class E>
bool Graph<T,E>::removeVertex(int v)    //充分利用要被删除的那一行,那一列的空间,替换为最后一行,一列,numVertex--
{
    if (v<0||v>=numVertices)return false;   //顶点不在图中
    if (numVertices==1) return false;       //只剩一个顶点,不删除
    VerticesList[v]=VerticesList[numVertices-1];//顶点表中删除该结点
    for (int i=0; i<numVertices; i++)
    {
        if (Edge[v][i]>0&&Edge[v][i]<maxWeight)
        {
            //Edge[v][i]=Edge[i][v]=maxWeight;
            numEdges--;
        }
    }
    for (int i=0; i<numVertices; i++)       //用最后一列填补第v列
    {
        Edge[i][v] = Edge[i][numVertices-1];
        Edge[i][numVertices-1] = maxWeight;
    }
    for (int i=0; i<numVertices; i++)       //用最后一行填补第v行
    {
        Edge[v][i]=Edge[numVertices-1][i];
        Edge[numVertices-1][i]=maxWeight;
    }
    Edge[numVertices-1][numVertices-1]=0;   //对角线为0
    numVertices--;                          //顶点数减一
    return true;
}

template <class T,class E>
bool Graph<T,E>::removeEdge(int v1, int v2)
{
    if (v1>-1&&v1<numVertices&&v2>-1&&v2<numVertices&&Edge[v1][v2]>0&&Edge[v1][v2]<maxWeight)
    {
        Edge[v1][v2]=Edge[v2][v1]=maxWeight;
        numEdges--;
        return true;
    }
    return false;
}

template <class T,class E>
istream& operator>>(istream& in,Graph<T, E> &g)
{
    int i,j,k,n,m;
    T e1,e2;
    E weight;
    cout<<"输入顶点数n和变数m"<<endl;
    in>>n>>m;
    cout<<"输入"<<n<<"个顶点的信息"<<endl;
    for (i=0; i<n; i++)
    {
        in>>e1;
        g.insertVertex(e1);
    }
    i=0;
    cout<<"输入"<<m<<"条边的信息\n端点e1 端点e2 权重"<<endl;
    while(i<m)
    {
        in>>e1>>e2>>weight;
        j=g.getVertexPosition(e1);
        k=g.getVertexPosition(e2);
        if (j==-1||k==-1) {
            cout<<"边两端信息有误,重新输入这条边"<<endl;
        }
        else
        {
            g.insertEdge(e1, e2, weight);
        }
    }
    return in;
}
template <class T,class E>
ostream& operator<<(ostream& out,Graph<T, E> &g)
{
    int i,j,n,m;T e1,e2;E w;
    n=g.numberOfVertices();
    m=g.numberOfEdge();
    out<<n<<","<<m<<endl;
    for (i=0; i<n; i++) {
        for (j=i+1; j<n; j++)
        {
            w=g.getWeight(i, j);
            if (w>0&&w<w<maxWeight) {
                e1 = g.getValue(i);
                e2 = g.getValue(j);
                out<<"("<<e1<<","<<e2<<","<<w<<")"<<endl;
            }
        }

    }
    return out;
}
template <class T,class E>
void Graph<T,E>::input()
{
    int i,j,k,n,m;
    T e1,e2;
    E weight;
    cout<<"输入顶点数n和变数m"<<endl;
    cin>>n>>m;
    cout<<"输入"<<n<<"个顶点的信息"<<endl;
    for (i=0; i<n; i++)
    {
        cin>>e1;
        insertVertex(e1);
    }
    i=0;
    cout<<"输入"<<m<<"条边的信息\n端点e1 端点e2 权重"<<endl;
    while(i<m)
    {
        cin>>e1>>e2>>weight;
        j=getVertexPosition(e1);
        k=getVertexPosition(e2);
        if (j==-1||k==-1) {
            cout<<"边两端信息有误,重新输入这条边"<<endl;
        }
        else
        {
            insertEdge(j, k, weight);
            i++;
        }
    }
    
}
template <class T,class E>
void Graph<T,E>::output()
{
    int i,j,n,m;T e1,e2;E w;
    n=numberOfVertices();
    m=numberOfEdge();
    cout<<n<<","<<m<<endl;
    for (i=0; i<n; i++) {
        for (j=i+1; j<n; j++)
        {
            w=getWeight(i, j);
            if (w>0&&w<w<maxWeight) {
                e1 = getValue(i);
                e2 = getValue(j);
                cout<<"("<<e1<<","<<e2<<","<<w<<")"<<endl;
            }
        }
        
    }
    
}
template <class T,class E>
void Graph<T,E>::outputAsMatrix()
{
    int i,j,n,m;T e1,e2;E w;
    n=numberOfVertices();
    m=numberOfEdge();
    cout<<n<<","<<m<<endl;
    cout<<"   ";
    for (int i=0; i<n; i++) {
        cout<<VerticesList[i]<<"  ";
    }
    cout<<endl;
    for (i=0; i<n; i++) {
        cout<<VerticesList[i]<<" ";
        for (j=0; j<n; j++)
        {
            w=getWeight(i, j);
            cout<<w<<" ";
        }
        cout<<endl;
    }
}

//邻接矩阵图的深度优先搜索
template <class T,class E>
void DFS(Graph<T,E> *G,const T v)
{
    int n = G->numberOfVertices();
    bool *visit = new bool[n];
    for (int i=0; i<n; i++)visit[i]=false;
    int index = G->getVertexPosition(v);
    DFS(G, index, visit);
    delete []visit;
        
}
template <class T,class E>
void DFS(Graph<T,E> *G,int v,bool visit[])
{
    cout<<G->getValue(v)<<" ";
    visit[v]=1;
    int w = G->getFirstNeighbor(v);
    while (w!=-1)
    {
        if (visit[w]==false) DFS(G, w, visit);
        w=G->getNextNeighbor(v, w);
    }
}

//邻接矩阵图的广度遍历
template <class T,class E>
void BFS(Graph<T,E> *G,const T v)
{
    int index = G->getVertexPosition(v);
    if (index==-1) return;
    queue<int > q ;
    q.push(index);
    int n = G->numberOfVertices();
    bool *visited = new bool[n];
    for (int i=0; i<n; i++)visited[i]=false;
    visited[index]=true;
    int temp;
    while (!q.empty())
    {
        temp = q.front();q.pop();
        cout<<G->getValue(temp)<<" ";
        
        int w = G->getFirstNeighbor(temp);
        while (w!=-1) {
            if (visited[w]==false) {q.push(w);visited[w]=true;}
            w = G->getNextNeighbor(temp, w);
        }
    }
    
}
/*测试数据 9 10 A B C D E F G H I
 A D 1
 A C 1
 A B 1
 B E 1
 B C 1
 E G 1
 D F 1
 C F 1
 F H 1
 H I 1
 */
int main(int argc, const char * argv[])
{
    Graph<char, int > *graph = new Graph<char, int>(20);
    graph->input();
    graph->output();
    graph->outputAsMatrix();
    DFS(graph, 'A');
    cout<<endl;
    cout<<"广度遍历"<<endl;
    BFS(graph, 'A');
    return 0;
}