图的操作


一、实验目的

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

二、实验内容

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);

 

   }

}


原文地址:https://www.cnblogs.com/qiaoshanzi/p/2283377.html