HNU图的实现(邻接表和邻接矩阵)

该文主要讨论了图的两种表示方法——邻接表和邻接矩阵,并提供了对应的C++类实现。Graphl类实现了邻接表表示法,而Graphm类实现了邻接矩阵表示法,它们都继承自抽象基类Graph。每个类中包含了计算顶点入度和出度、深度优先搜索、广度优先搜索、Dijkstra算法以及Prim算法的相关方法。此外,还包含了链表和列表操作的模板类定义。
摘要由CSDN通过智能技术生成

【问题描述】

         在本问题,定义了图的两种表示方法:邻接表(链表)表示法及邻接矩阵表示法。

         头文件graph.h定义了图的ADT类Graph,头文件grlist.h中定义的类Graphl,实现了使用图的邻接表表示法,头文件grmat.h中定义的类Graphm,实现了图的邻接矩阵表示法,都是Graph类的子类,分别实现了Graph类中定义的所有纯虚方法。

        头文件Graph_test.h中的类option定义了图的相关算法。

        头文件link.h、list.h、llist.h定义了链表的相关操作。

        文件main.cpp为主函数源文件,其中包含了所有针对图的输入以及所有测试选项。

        graphAlg.cbp为基于Code::Blocks的项目文件。

你的任务是:

你需要打开头文件grlist.h以及grmat.h,在函数getInDegree以及getOutDegree处填写相关代码,测试完成第1项任务。

你需要打开头文件Graph_test.h,填写相关代码,完成第2~5项任务。

除以上文件相应的位置外,请不要改变其他任何代码,否则将可能不能通过测试。

代码填写时,不必完成所有任务,任何任务都可以单独测试,建议你一项一项完成,提交代码时请将所有头文件以及源文件打包压缩提交。

测试用例有20个:

    1~4:用于测试入度/出度

    5~8:用于测试DFS算法

    9~12:用于测试BFS算法

    13~16:用于测试Dijkstra算法

    17~20:用于测试prim算法

【输入形式】     输入的第一行为一个整数choice,表示需要测试(执行)的操作或算法

    1.求所有顶点的入度和出度 

     2.深度优先搜索(遍历)

     3.广度优先搜索(遍历) 

     4.Dijkstra求最短路(从0点出发至其他各点)

     5.prim算法求最小支撑树(从0点出发至其他各点)

       输入的第二行为一个整数vert_num,表示树的节点数,编号从0~vert_num-1

       输入的第三行为一个整数graph_type,表示用哪种方法存储图:

         0.用邻接矩阵表示法

         1.用邻接表表示法

       输入的第四行为一个字符graph_dir:

         U.无向图

         D.有向图

       接下来的若干行,每行三个参数,表示图的边,第一个参数为出点,第二个参数为入点,第三个参数为边长(权重)

【注意】输入结束务必使用:“回车 Ctrl+Z 回车”的方式

【输出形式】

       根据第一个参数choice的选择不同,输出对应不同的结果,具体请参照样例输出。

【样例输入1】

1
6               
1
U               
0 4 9           
0 2 7
2 3 1
2 1 5
2 5 2
1 5 6
3 5 2

【样例输出1】

2 2 4 2 1 3
2 2 4 2 1 3

"graph.h"的代码

//graph.h

// From the software distribution accompanying the textbook
// "A Practical Introduction to Data Structures and Algorithm Analysis,
// Third Edition (C++)" by Clifford A. Shaffer.
// Source code Copyright (C) 2007-2011 by Clifford A. Shaffer.

// Graph abstract class. This ADT assumes that the number
// of vertices is fixed when the graph is created.
#ifndef GRAPH
#define GRAPH

class Graph {
private:
  void operator =(const Graph&) {}     // Protect assignment
  Graph(const Graph&) {}         // Protect copy constructor

public:
  Graph() {}          // Default constructor
  virtual ~Graph() {} // Base destructor

  // Initialize a graph of n vertices
  //初始化图 
  virtual void Init(int n) =0;

  // Return: the number of vertices and edges
  //返回顶点数和边数 
  virtual int n() =0;
  virtual int e() =0;

  // Return v's first neighbor
  //返回顶点v的第一个邻接点 
  virtual int first(int v) =0;

 // Return v's next neighbor
 //返回顶点v的下一个邻接点 
  virtual int next(int v, int w) =0;

  // Set the weight for an edge
  //给边赋权值 
  // i, j: The vertices
  // wgt: Edge weight
  virtual void setEdge(int v1, int v2, int wght) =0;

  // Delete an edge
  //删除边 
  // i, j: The vertices
  virtual void delEdge(int v1, int v2) =0;

  // Determine if an edge is in the graph
  //判断两点间是否有边 
  // i, j: The vertices
  // Return: true if edge i,j has non-zero weight
  virtual bool isEdge(int i, int j) =0;

  // Return an edge's weight
  //返回边的权值 
  // i, j: The vertices
  // Return: The weight of edge i,j, or zero
  virtual int weight(int v1, int v2) =0;

  // Get and Set the mark value for a vertex
  //获取/设置点的标记量 
  // v: The vertex
  // val: The value to set
  virtual int getMark(int v) =0;
  virtual void setMark(int v, int val) =0;
  
  //返回点的入度与出度	
  virtual int getInDegree(int v) = 0;
  virtual int getOutDegree(int v) = 0;
};
#endif // GRAPH



"link.h"的代码

//link.h

#include <iostream> 
template <typename E> class Link {
public:
  E element;      // 结点值 
  Link *next;        // 结点指针:在链表中指向下一结点
  // 构造函数
  Link(const E& elemval, Link* nextval =NULL)
    { element = elemval;  next = nextval; }
  Link(Link* nextval =NULL) { next = nextval; }
};

"list.h"的代码

//list.h

#ifndef LIST
#define LIST
template <typename E> class List { // List ADT
private:
  void operator =(const List&) {}      // Protect assignment   
  List(const List&) {}           // Protect copy constructor 
public:
  List() {}          // 默认构造函数 
  virtual ~List() {} // 基本的析构函数 

  // 从列表中清除内容,让它空着
  virtual void clear() = 0;

  // 在当前位置插入一个元素
  // item: 要插入的元素
  virtual void insert(const E& item) = 0;

  // 在列表的最后添加一个元素 
  // item: 要添加的元素 
  virtual void append(const E& item) = 0;

  // 删除和返回当前元素 
  // Return: 要删除的元素 
  virtual E remove() = 0;

  // 将当前位置设置为列表的开始
  virtual void moveToStart() = 0;

  // 将当前位置设置为列表的末尾 
  virtual void moveToEnd() = 0;

  // 将当前位置左移一步,如果当前位置在首位就不变 
  virtual void prev() = 0;

  // 将当前位置右移一步,如果当前位置在末尾就不变 
  virtual void next() = 0;

  // 返回列表当前元素个数 
  virtual int length() const = 0;

  // 返回当前位置 
  virtual int currPos() const = 0;

  // 设置当前位置 
  // pos: 要设置的当前位置 
  virtual void moveToPos(int pos) = 0;

  // Return: 当前位置的元素 
  virtual const E& getValue() const = 0;
};
#endif

"llist.h"的代码

//llist.h

#include "list.h"
#include<assert.h>

// This is the declaration for LList. It is split into two parts
// because it is too big to fit on one book page
// Linked list implementation
using namespace std;
template <typename E> class LList: public List<E> {
private:
  Link<E>* head;       // 指向链表头结点 
  Link<E>* tail;       // 指向链表最后一个结点 
  Link<E>* curr;       // 指向当前元素 
  int cnt;    	       // 当前列表大小 

  void init() {        // 初始化
    curr = tail = head = new Link<E>;
    cnt = 0;
  }

  void removeall() {   // Return link nodes to free store 
    while(head != NULL) {
      curr = head;
      head = head->next;
      delete curr;
    }
  }

public:
  LList(int size=100) { init(); }    // 构造函数 
  ~LList() { removeall(); }                   // 析构函数
  void print() const;                // 打印列表内容
  void clear() { removeall(); init(); }       // 清空列表

  // 在当前位置插入“it”
  void insert(const E& it) {
    curr->next = new Link<E>(it, curr->next);  
    if (tail == curr) tail = curr->next;  //新的尾指针 
    cnt++;
  }

  void append(const E& it) { // 追加“it”到列表中
    tail = tail->next = new Link<E>(it, NULL);
    cnt++;
  }

  // 删除并返回当前元素
  E remove() {
    assert(curr->next != NULL);//"No element"
    E it = curr->next->element;      // 保存元素值
    Link<E>* ltemp = curr->next;     // 保存指针域信息 
    if (tail == curr->next) tail = curr; // 重置尾指针
    curr->next = curr->next->next;   // 从列表中删除 
    delete ltemp;                    //回收空间
    cnt--;			     // 当前列表大小减一
    return it;
  }

  void moveToStart() // 将curr设置在列表头部
    { curr = head; }

  void moveToEnd()   // 将curr设置在列表尾部
    { curr = tail; }

  // 将curr指针往前(左)移一步;如果已经指向头部了就不需要改变 
  void prev() {
    if (curr == head) return;       // 之前没有元素 
    Link<E>* temp = head;
    // March down list until we find the previous element
    while (temp->next!=curr) temp=temp->next;
    curr = temp;
  }

  // 将curr指针往后(右)移一步;如果已经指向尾部了就不需要改变 
  void next()
    { if (curr != tail) curr = curr->next; }

  int length() const  { return cnt; } // 返回当前列表大小

  // 返回当前元素的位置
  int currPos() const {
    Link<E>* temp = head;
    int i;
    for (i=0; curr != temp; i++)
      temp = temp->next;
    return i;
  }

  // 向下移动到列表“pos”位置
  void moveToPos(int pos) {
    assert ((pos>=0)&&(pos<=cnt));//"Position out of range"
    curr = head;
    for(int i=0; i<pos; i++) curr = curr->next;
  }

  const E& getValue() const { // 返回当前元素
    assert(curr->next != NULL);//"No value"
    return curr->next->element;
  }
};

"grlist.h"的代码

//grlist.h

// From the software distribution accompanying the textbook
// "A Practical Introduction to Data Structures and Algorithm Analysis,
// Third Edition (C++)" by Clifford A. Shaffer.
// Source code Copyright (C) 2007-2011 by Clifford A. Shaffer.

// Include this file to access Graph representation implemented using an
// Adjacency List
# ifndef GRLIST
# define GRLIST

#include <stdio.h>
#include <ctype.h>
#include <assert.h>
// Used by the mark array
#define UNVISITED 0
#define VISITED 1

#include "link.h"
#include "llist.h"

#include "graph.h"


// Edge class for Adjacency List graph representation
class Edge
{
    int vert, wt;
public:
    Edge()
    {
        vert = -1;
        wt = -1;
    }
    Edge(int v, int w)
    {
        vert = v;
        wt = w;
    }
    int vertex()
    {
        return vert;
    }
    int weight()
    {
        return wt;
    }
};



class Graphl : public Graph
{
private:
    List<Edge>** vertex;        // List headers
    int numVertex, numEdge;     // Number of vertices, edges
    int *mark;                  // Pointer to mark array
public:
    Graphl(int numVert)
    {
        Init(numVert);
    }

    ~Graphl()         // Destructor
    {
        delete [] mark; // Return dynamically allocated memory
        for (int i = 0; i < numVertex; i++) delete [] vertex[i];
        delete [] vertex;
    }

    void Init(int n)
    {
        int i;
        numVertex = n;
        numEdge = 0;
        mark = new int[n];  // Initialize mark array
        for (i = 0; i < numVertex; i++) mark[i] = UNVISITED;
        // Create and initialize adjacency lists
        vertex = (List<Edge>**) new List<Edge>*[numVertex];
        for (i = 0; i < numVertex; i++)
            vertex[i] = new LList<Edge>();
    }

    int n()
    {
        return numVertex;    // Number of vertices
    }
    int e()
    {
        return numEdge;    // Number of edges
    }

    int first(int v)   // Return first neighbor of "v"
    {
        if (vertex[v]->length() == 0)
            return numVertex;      // No neighbor
        vertex[v]->moveToStart();
        Edge it = vertex[v]->getValue();
        return it.vertex();
    }

    // Get v's next neighbor after w
    int next(int v, int w)
    {
        Edge it;
        if (isEdge(v, w))
        {
            if ((vertex[v]->currPos() + 1) < vertex[v]->length())
            {
                vertex[v]->next();
                it = vertex[v]->getValue();
                return it.vertex();
            }
        }
        return n(); // No neighbor
    }
    // Set edge (i, j) to "weight"
    void setEdge(int i, int j, int weight)
    {
//   Assert(weight>0, "May not set weight to 0");
        assert(weight > 0);
        Edge currEdge(j, weight);
        if (isEdge(i, j))   // Edge already exists in graph
        {
            vertex[i]->remove();
            vertex[i]->insert(currEdge);
        }
        else   // Keep neighbors sorted by vertex index
        {
            numEdge++;
            for (vertex[i]->moveToStart();
                    vertex[i]->currPos() < vertex[i]->length();
                    vertex[i]->next())
            {
                Edge temp = vertex[i]->getValue();
                if (temp.vertex() > j) break;
            }
            vertex[i]->insert(currEdge);
        }
    }

    void delEdge(int i, int j)    // Delete edge (i, j)
    {
        if (isEdge(i, j))
        {
            vertex[i]->remove();
            numEdge--;
        }
    }

    bool isEdge(int i, int j)   // Is (i,j) an edge?
    {
        Edge it;
        for (vertex[i]->moveToStart();
                vertex[i]->currPos() < vertex[i]->length();
                vertex[i]->next())              // Check whole list
        {
            Edge temp = vertex[i]->getValue();
            if (temp.vertex() == j) return true;
        }
        return false;
    }

    int weight(int i, int j)   // Return weight of (i, j)
    {
        Edge curr;
        if (isEdge(i, j))
        {
            curr = vertex[i]->getValue();
            return curr.weight();
        }
        else return 0;
    }

    int getMark(int v)
    {
        return mark[v];
    }
    void setMark(int v, int val)
    {
        mark[v] = val;
    }

    int getInDegree(int v)   // 求顶点v的入度
    {
        int result = 0;

        //............... 在此行以下插入补充代码
        for(int i=0;i<n();i++)
        {
            if(i!=v)
            {
               if(isEdge(i,v))
                  result++;
             }
        }

        //............... 在此行以上插入补充代码
        return result;
    }

    int getOutDegree(int v)    // 求顶点v的出度
    {
        int result=0;
         //............... 在此行以下插入补充代码
         result=vertex[v]->length();


        //............... 在此行以上插入补充代码
        return result;
    }
};

# endif // GRLIST

"grmat.h"的代码

//grmat.h

// From the software distribution accompanying the textbook
// "A Practical Introduction to Data Structures and Algorithm Analysis,
// Third Edition (C++)" by Clifford A. Shaffer.
// Source code Copyright (C) 2007-2011 by Clifford A. Shaffer.

// Include this file to access Graph representation implemented using an
// Adjacency Matrix.
#ifndef GRMATH
#define GRMATH

#include <stdio.h>
#include <ctype.h>
#include <assert.h>
// Used by the mark array
#define UNVISITED 0
#define VISITED 1

#include "graph.h"

// Implementation for the adjacency matrix representation
class Graphm : public Graph
{
private:
    int numVertex, numEdge; // Store number of vertices, edges
    int **matrix;           // Pointer to adjacency matrix
    int *mark;              // Pointer to mark array
public:
    Graphm(int numVert)     // Constructor
    {
        Init(numVert);
    }

    ~Graphm()         // Destructor
    {
        delete [] mark; // Return dynamically allocated memory
        for (int i = 0; i < numVertex; i++)
            delete [] matrix[i];
        delete [] matrix;
    }

    void Init(int n)   // Initialize the graph
    {
        int i;
        numVertex = n;
        numEdge = 0;
        mark = new int[n];     // Initialize mark array
        for (i = 0; i < numVertex; i++)
            mark[i] = UNVISITED;
        matrix = (int**) new int*[numVertex]; // Make matrix
        for (i = 0; i < numVertex; i++)
            matrix[i] = new int[numVertex];
        for (i = 0; i < numVertex; i++) // Initialize to 0 weights
            for (int j = 0; j < numVertex; j++)
                matrix[i][j] = 0;
    }

    int n()
    {
        return numVertex;    // Number of vertices
    }
    int e()
    {
        return numEdge;    // Number of edges
    }

    // Return first neighbor of "v"
    int first(int v)
    {
        for (int i = 0; i < numVertex; i++)
            if (matrix[v][i] != 0) return i;
        return numVertex;           // Return n if none
    }

    // Return v's next neighbor after w
    int next(int v, int w)
    {
        for(int i = w + 1; i < numVertex; i++)
            if (matrix[v][i] != 0)
                return i;
        return numVertex;           // Return n if none
    }

    // Set edge (v1, v2) to "wt"
    void setEdge(int v1, int v2, int wt)
    {
//   Assert(wt>0, "Illegal weight value");
        assert(wt > 0);
        if (matrix[v1][v2] == 0) numEdge++;
        matrix[v1][v2] = wt;
    }

    void delEdge(int v1, int v2)   // Delete edge (v1, v2)
    {
        if (matrix[v1][v2] != 0) numEdge--;
        matrix[v1][v2] = 0;
    }

    bool isEdge(int i, int j) // Is (i, j) an edge?
    {
        return matrix[i][j] != 0;
    }

    int weight(int v1, int v2)
    {
        return matrix[v1][v2];
    }
    int getMark(int v)
    {
        return mark[v];
    }
    void setMark(int v, int val)
    {
        mark[v] = val;
    }

    int getInDegree(int v)   // 求顶点v的入度
    {
        int result = 0;

        //............... 在此行以下插入补充代码
        for(int i=0;i<numVertex;i++)
        {
            if(matrix[i][v]!=0)
               result++;
        }
        //............... 在此行以上插入补充代码
        return result;
    }

    int getOutDegree(int v)    // 求顶点v的出度
    {
        int result = 0;
        //............... 在此行以下插入补充代码
        for(int i=0;i<numVertex;i++)
        {
            if(matrix[v][i]!=0)
               result++;
        }
        //............... 在此行以上插入补充代码
        return result;
    }
};
# endif // GRMATH

"Graph_test.h"的代码

//Graph_test.h

#ifndef GRAPH_TEST_H_INCLUDED
#define GRAPH_TEST_H_INCLUDED
#define INFINITY 1000000
#include <queue>

class option
{
private:
    Graph *G;
public:
// Start with some implementations for the abstract functions
    option(Graph *g)
    {
        G = g;
    }


    void DFS(int v, void (*PreVisit)(int v), void (*PostVisit)(int v), void (*Visiting)(int v))   // Depth first search
    {
         PreVisit(v);
         Visiting(v);
         G->setMark(v,VISITED);
         for(int w=G->first(v);w<G->n();w=G->next(v,w))
         {
              if(G->getMark(w)==UNVISITED)
              DFS(w,(*PreVisit),(*PostVisit),(*Visiting));
          }
          PostVisit(v);

    }

    void BFS(int start, void (*PreVisit)(int v), void (*PostVisit)(int v), void (*Visiting)(int v))
    {
         int v=0,w=0;
         queue<int>q;
         q.push(start);
         G->setMark(start,VISITED);
         while(q.size()!=0)
        {
           v=q.front();
           q.pop();
           if(v==start) PreVisit(v);
           Visiting(v);
           for(w=G->first(v);w<G->n();w=G->next(v,w))
              if(G->getMark(w)==UNVISITED)
              {
                  PreVisit(w);
                  G->setMark(w,VISITED);
                  q.push(w);
               }
           PostVisit(v);
         }
    }

    void Dijkstra1(int* D, int s)
    {
         int v,w,i;
         for(i=0;i<G->n();i++)
         {
             v=minVertex(D);
             if(D[v]==INFINITY) return;
             G->setMark(v,VISITED);
             for(w=G->first(v);w<G->n();w=G->next(v,w))
             if(D[w]>(D[v]+weight(v,w))
                D[w]=D[v]+weight(v,w);
         }

    }

    int minVertex(int* D)   // Find min cost vertex
    {
        int i, v = -1;
        // Initialize v to some unvisited vertex
        for (i = 0; i < G->n(); i++)
            if (G->getMark(i) == UNVISITED)
            {
                v = i;
                break;
            }
        for (i++; i < G->n(); i++) // Now find smallest D value
            if ((G->getMark(i) == UNVISITED) && (D[i] < D[v]))
                v = i;
        return v;
    }

    void AddEdgetoMST(int v1, int v2)
    {
        cout << "Add edge " << v1 << " to " << v2 << "\n";
    }
    void Prim(int* D, int s)   // Prim's MST algorithm
    {
         int V[G->n()];
         int i,w;
         for(i=0;i<G->n();i++)
         {
              int v=minVertex(D);
              G->setMark(v,VISITED);
              if(v!=s)
              AddEdgetoMST(V[v],v);
              if(D[v]==INFINITY)  return;
              for(w=G->first(v);w<G->n();w=G->next(v,w))
              if(D[w]>weight(v,w))
              {
                  D[w]=weight(v,w);
                  V[w]=v;
              }
         }
    }
};

#endif // GRAPH_TEST_H_INCLUDED

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值