zoukankan      html  css  js  c++  java
  • 图的操作


    一、实验目的

    掌握图的基本概念,描述方法;遍历方法。

    二、实验内容

    1、创建图类。二叉树的存储结构使用邻接矩阵或链表。

    2、提供操作:遍历、BFS、DFS

    3、对建立好的图,执行上述各操作。

    4、输出生成树。

    1、 输出最小生成树。

    三、最小生成树的思想

    (1)、2个for循环都是从2开始的,因为一般我们默认开始就把第一个节点加入生成树,因此之后不需要再次寻找它。
    ( 2)、lowcost[i]记录的是以节点i为终点的最小边权值。初始化时因为默认把第一个节点加入生成树,因此lowcost[i] = graph[1][i],即最小边权值就是各节点到1号节点的边权值中最小的。
    ( 3)mst[i]记录的是lowcost[i]对应的起点,这样有起点,有终点,即可唯    一确定一条边了。初始化时mst[i] = 1,即每条边都是从1号节点出发。

    四、程序代码

    #include <iostream>

    using namespace std;

    //队列

    template <class T>

    class Node

    {

    public:

     Node(){}

     virtual ~Node(){}

     T data;

     Node<T> *link;

    };

    template<class T>

    class LinkedQueue

    {

    public:

     LinkedQueue();

     virtual ~LinkedQueue();

     bool IsEmpty() const{return ((front)?false:true);}

     LinkedQueue<T>& Add(const T& x);

     LinkedQueue<T>& Delete(T& x);

    public:

     Node<T> *front;

     Node<T> *rear;

    };

    template <class T>

    LinkedQueue<T>::LinkedQueue()

    {

     front=rear=0;

    }

    template <class T>

    LinkedQueue<T>::~LinkedQueue()

    {

     Node<T> *next;

     while(front)

     {

      next=front->link;

      delete front;

      front=next;

     }

    }

    template <class T>

    LinkedQueue<T>& LinkedQueue<T>::Add(const T& x)

    {

     Node<T> *p=new Node<T>;

     p->data=x;

     p->link=0;

     if(front)

     rear->link=p;

     else front=p;

     rear=p;

     return *this;

    }

    template <class T>

    LinkedQueue<T>& LinkedQueue<T>::Delete(T& x)

    {

     if(IsEmpty())

     {

     return *this;

     }

     x=front->data;

     Node<T> *p=front;

     front=front->link;

     delete p;

     return *this;

    }

    //加权有向图

    template <class T>

    class AdjacencyWDigraph

    {

    public:

     AdjacencyWDigraph(int Vertices = 10,T noEdge=0);

     virtual ~AdjacencyWDigraph(){Delete2DArray(a,n+1);}

     bool Exist(int i,int j) const;

     int Edges() const {return e;}

     int Vertices() const {return n;}

     AdjacencyWDigraph<T>& Add(int i,int j ,const T& w);

     AdjacencyWDigraph<T>& Delete(int i,int j);

     int OutDegree(int i) const;

     int InDegree(int i) const;

     void Make2DArray(T ** &x,int rows,int cols);

     void Delete2DArray(T ** &x,int rows);

      //遍历

     void InitializePos(){pos=new int[n+1];}

     void DeactivatePos(){delete [] pos;}

     int Begin(int i);

     int NextVertex(int i);

     //宽度优先搜索

     void BFS(int v,int reach[],int label);

     //深度优先搜索

     void DFS(int v,int reach[],int label);

     void dfs(int v,int reach[],int label);

    public:

     T NoEdge;

     int n;

     int e;

     T **a;

     int *pos;

    };

    template <class T>

    AdjacencyWDigraph<T>::AdjacencyWDigraph(int Vertices ,T noEdge)

    {

     n = Vertices;

     e = 0;

     NoEdge = noEdge;

     Make2DArray(a,n+1,n+1);

     for(int i =1;i <= n;i++)

     for(int j =1;j <=n;j++)

      a[i][j] = NoEdge;

    }

    template <class T>

    bool AdjacencyWDigraph<T>::Exist(int i,int j) const

    {

     if(i<1 || j<1 || i>n || j>n || a[i][j]==NoEdge)

     return false;

     return true;

    }

    template <class T>

    AdjacencyWDigraph<T>& AdjacencyWDigraph<T>::Add(int i,int j ,const T&w)

    {

        if(i<1 || j<1 || i>n || j>n || i==j || a[i][j]!=NoEdge)

           cout<<"zzzzzzzzzzzzzzzzzzzzzzz"<<endl;

     a[i][j] = w;

     e++;

     cout <<"a["<<i<<"]["<<j<<"]="<<a[i][j]<<endl;

     return *this;

    }

    template <class T>

    AdjacencyWDigraph<T>& AdjacencyWDigraph<T>::Delete(int i,int j)

    {

     if(i<1 || j<1 || i>n || j>n || a[i][j]==NoEdge)

               throw BadInput();

       a[i][j] =NoEdge;

     e--;

     return *this;

    }

    template <class T>

    int AdjacencyWDigraph<T>::OutDegree(int i) const

    {

     if(i<1 || i>n)

           cout<<xxxxxxxxxxxxxxxxxxxxxxxxxx<<endl;

     int sum=0;

     for(int j=1;j<=n;j++)

     if(a[i][j] !=NoEdge)

      sum++;

     return sum;

    }

    template <class T>

    int AdjacencyWDigraph<T>::InDegree(int i) const

    {

       if(i<1 || i>n) throw BadInput();

     int sum=0;

     for(int j=1;j<=n;j++)

     if(a[j][i] !=NoEdge)

      sum++;

     return sum;

    }

    template <class T>

    void AdjacencyWDigraph<T>::Make2DArray(T ** &x,int rows,int cols)

    {

     x=new T * [rows];

     for(int i=0;i<rows;i++)

     x[i]=new int [cols];

    }

    template <class T>

    void AdjacencyWDigraph<T>::Delete2DArray(T ** &x,int rows)

    {

     for(int i=0;i<rows;i++)

     delete [] x[i];

     delete [] x;

     x=0;

    }

    //遍历

    template <class T>

    int AdjacencyWDigraph<T>::Begin(int i)

    {

     if(i<1 || i>n)

           cout<<"qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"<<endl;

      

     for(int j=1;j<=n;j++)

     if(a[i][j] != NoEdge)

     {

      pos[i]=j;

      return j;

     }

     pos[i]=n+1;

     return 0;

    }

    template <class T>

    int AdjacencyWDigraph<T>::NextVertex(int i)

    {

     if(i<1 || i>n)

           cout<<"sassssssssssssssssssssssssssssssss"<<endl;

      

     for(int j=pos[i]+1;j<=n;j++)

     if(a[i][j] != NoEdge)

     {

      pos[i]=j;

      return j;

     }

     pos[i]=n+1;

     return 0;

    }

    //宽度优先搜索

    template <class T>

    void AdjacencyWDigraph<T>::BFS(int v,int reach[],int label)

    {

     LinkedQueue<int> Q;

     InitializePos();

     reach[v]=label;

     Q.Add(v);

     while(!Q.IsEmpty())

     {

     int w;

     Q.Delete(w);

     cout<< w <<" ";

     int u=Begin(w);

     while(u)

     {

      if(reach[u] !=label)

      {

       Q.Add(u);

       reach[u]=label;

      }

      u=NextVertex(w);    

     }

     }

     DeactivatePos();

    }

     //深度优先搜索

    template <class T>

    void AdjacencyWDigraph<T>::DFS(int v,int reach[],int label)

    {

     InitializePos();

     dfs(v,reach,label);

     DeactivatePos();

    }

    template <class T>

    void AdjacencyWDigraph<T>::dfs(int v,int reach[],int label)

    {

     cout<<v<<" ";

     reach[v]=label;

     int u=Begin(v);

     while(u)

     {

     if(reach[u] !=label)

      dfs(u,reach,label);

     u=NextVertex(v);

     }

    }

    //加权无向图

    template <class T>

    class AdjacencyWGraph : public AdjacencyWDigraph<T>

    {

    public:

     AdjacencyWGraph(int Vertices = 10,T noEdge=0):AdjacencyWDigraph<T>(Vertices,noEdge){}

     AdjacencyWGraph<T>& Add(int i,int j ,const T& w)

     {

     AdjacencyWDigraph<T>::Add(i,j,w);

     a[j][i]=w;

     cout <<"a["<<j<<"]["<<i<<"]="<<w<<endl;

     return *this;

     }

       AdjacencyWGraph<T>& Delete(int i,int j)

     {

     AdjacencyWDigraph<T>::Delete(i,j);

     a[j][i]=NoEdge;

     return *this;

     }

     int Degree(int i) const {return OutDegree(i);}

    #define INF 999999 ;

    void Prim(int n, int **c)

    {

      int *lowcost;

      int *closest;

      bool *s;

      lowcost = new int[n];

      closest = new int[n];

      s = new bool[n];

      s[1] = true;

      for(int i=1;i<=n;i++)

      {

         lowcost[i] = c[1][i];

         closest[i]=1;

         s[i] = false;

      }

      cout<<"最小生成树为:"<<endl;

      for(i=1;i<n;i++)

      {

         int min = INF;

         int j=1;

         for(int k=2;k<=n;k++)

            if((lowcost[k]<min) && (!s[k]))

      {

              min=lowcost[k];

              j=k;

      }                    

         cout<<closest[j]<<" "<<j<<endl;

         s[j]=true;

        for(k=2;k<=n;k++)

           if((c[j][k]<lowcost[k]) && (!s[k]))

     {

              lowcost[k] = c[j][k];

              closest[k] = j;

     }

    }

    }

    };

    void main()

    {

          //初始一个加权有向图

    cout<<"建立加权有向图:"<<endl;

    int n1,n2,a,b,c;

    cout<<"输入建立有向图的节点个数、边数: ";

    cin>>n1>>n2;

     AdjacencyWDigraph<int> graph(n1,0);

    for(int i=1;i<=n2;i++)

    {

    cout<<"输入第"<<i<<"个(输入顺序为:起点,终点,权值):  ";

    cin>>a>>b>>c;

    graph.Add(a,b,c);

    }

     //遍历

     graph.InitializePos();

     cout<<"遍历:"<<endl;

     cout<<"遍历所有从顶点i开始的下一顶点:(输入1—"<<n1<<")";

     int nn,x;

     cin >>nn;

     x = graph.Begin(nn);

       cout <<x<<endl;

     x = graph.NextVertex(nn);

    while(x!=0)

    {

          cout<<x<<endl;

          x = graph.NextVertex(nn);

    }

    //宽度优先搜索

     cout<<"宽度优先搜索 : "<<endl;

       int reach2[6];

     graph.BFS(1,reach2,9);

     cout<<endl;

     //深度优先搜索

     cout<<"深度优先搜索:"<<endl;

     int reach1[6];

     graph.DFS(1,reach1,9);

     cout<<endl;  

    //最小生成树

    // 

    cout<<"建立加权无向图:"<<endl;

    int nn1,nn2,a1,b1,c1;

    cout<<"输入建立无向图的节点个数、边数: ";

    cin>>nn1>>nn2;

     #define INF 999999

     AdjacencyWGraph<int> graph1(nn1,INF);

    for(int i1=1;i1<=nn2;i1++)

    {

    cout<<"输入第"<<i1<<"个(输入顺序为:起点,终点,权值):  ";

    cin>>a1>>b1>>c1;

    graph1.Add(a1,b1,c1);

    }

     graph1.Prim(nn1,graph1.a);

    }



    关于最小生成树的算法

    我使用的是Prim算法

    最小生成树之Prim算法

    1、生成树的概念
       连通图G的一个子图如果是一棵包含G的所有顶点的树,则该子图称为G的生成树。

      生成树是连通图的极小连通子图。所谓极小是指:若在树中任意增加一条边,则将出现一个回路;若去掉一条边,将会使之变成非连通图。生成树各边的权值总和称为生成树的权。权最小的生成树称为最小生成树。

    2、最小生成树的性质
      用哲学的观点来说,每个事物都有自己特有的性质,那么图的最小生成树也是不例外的。按照生成树的定义,n 个顶点的连通网络的生成树有 n 个顶点、n-1 条边。

    3、构造最小生成树,要解决以下两个问题:
    ( 1).尽可能选取权值小的边,但不能构成回路(也就是环)。
    (2).选取n-1条恰当的边以连接网的 n个顶点。

    求最小生成树的算法一般都使用贪心策略,有Prim算法和Krusal算法等。

    普里姆算法的基本思想:
    1)清空生成树,任取一个顶点加入生成树;
    2)在那些一个端点在生成树里,另一个端点不在生成树里的边中,选取一条权最小的边,将它和另一个端点加进生成树;
    3)重复步骤2,直到所有的顶点都进入了生成树为止,此时的生成树就是最小生成树。

    即:  从连通网络 N = { V, E }中的某一顶点 u0 出发,选择与它关联的具有最小权值的边(u0, v),将其顶点v加入到生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u, v),把它的顶点 v加入到集合U中。如此继续下去,直到网络中的所有顶点都加入到生成树顶点集合U中为止。

    编写程序:对于如下一个带权无向图,给出节点个数以及所有边权值,用Prim算法求最小生成树。


    代码的注释我写得很详细,方便理解,有几点需要说明一下。

    (1)、2个for循环都是从2开始的,因为一般我们默认开始就把第一个节点加入生成树,因此之后不需要再次寻找它。
    ( 2)、lowcost[i]记录的是以节点i为终点的最小边权值。初始化时因为默认把第一个节点加入生成树,因此lowcost[i] = graph[1][i],即最小边权值就是各节点到1号节点的边权值中最小的。
    ( 3)、mst[i]记录的是lowcost[i]对应的起点,这样有起点,有终点,即可唯一确定一条边了。初始化时mst[i] = 1,即每条边都是从1号节点出发。

    输入数据:
    7 11
    A B 7
    A D 5
    B C 8
    B D 9
    B E 7
    C E 5
    D E 15
    D F 6
    E F 8
    E G 9
    F G 11

    输出:
    A - D : 5
    D - F : 6
    A - B : 7
    B - E : 7
    E - C : 5
    E - G : 9
    Total:39

    最小生成树Prim算法朴素版 java语言实现 代码如下

    import java.util.*;

    public class Main { 

     static int MAXCOST=Integer.MAX_VALUE;

     

     static int Prim(int graph[][], int n){

      

      int lowcost[]=new int[n+1];

     

      

      int mst[]=new int[n+1];

     

      int min, minid, sum = 0;

     

      

       for (int i = 2; i <= n; i++){

           

           lowcost[i] = graph[1][i];

     

           

           mst[i] = 1;

        }

     

       

       mst[1] = 0;

     

       

       for (int i = 2; i <= n; i++){

           min = MAXCOST;

           minid = 0;

     

          

          for (int j = 2; j <= n; j++){

            

            if (lowcost[j] < min && lowcost[j] != 0){

               min = lowcost[j];

               minid = j;

            }

          }

        

          

           System.out.printf("%c - %c : %d\n", mst[minid] + 'A' - 1, minid + 'A' - 1, min);

     

          

          sum += min;

     

          

          lowcost[minid] = 0;

     

          

          for (int j = 2; j <= n; j++){

            

            if (graph[minid][j] < lowcost[j]){

                

                lowcost[j] = graph[minid][j];

     

                

                mst[j] = minid;

             }

          }

        }

        

           return sum;

      }

     

     public static void main(String args[]){

       Scanner sc=new Scanner(System.in);

       int cost;

       char chx, chy;

     

       

       int n=sc.nextInt();//节点

       int m=sc.nextInt();//边数

       int graph[][]=new int[n+1][n+1];

     

       

       for (int i = 1; i <= n; i++){

           for (int j = 1; j <= n; j++){

                  graph[i][j] = MAXCOST;

           }

       }

     

       

       for (int k = 0; k < m; k++){

           chx=sc.next().charAt(0);

           chy=sc.next().charAt(0);

           cost=sc.nextInt();

            int i = chx - 'A' + 1;

            int j = chy - 'A' + 1;

            graph[i][j] = cost;

            graph[j][i] = cost;

        }

     

       

        cost = Prim(graph, n);

     

       

        System.out.println("Total:"+cost);

     

       }

    }


  • 相关阅读:
    android学习——android项目的的目录结构
    android学习——android项目的的目录结构
    LA 4670 Dominating Patterns (AC自动机)
    HDU 2089 不要62 (递推+暴力或者数位DP)
    HDU 2504 又见GCD (最大公因数+暴力)
    HDU 2136 Largest prime factor (素数打表。。。)
    HDU 2138 How many prime numbers (判素数,米勒拉宾算法)
    HDU 3177 Crixalis's Equipment (贪心,差值)
    HDU 1718 Rank (排序)
    HDU 1716 排列2 (格式问题+排列)
  • 原文地址:https://www.cnblogs.com/qiaoshanzi/p/2283377.html
Copyright © 2011-2022 走看看