图的表示--邻接表

来源:互联网 发布:mac 终端更改时间date 编辑:程序博客网 时间:2024/06/05 04:49
图的表示:

       主要有两种,邻接矩阵和邻接表,前者空间复杂度,O(V2),后者为O(V+E)。因此,除非非常稠密的图(边非常多),一般后者优越于前者。

上篇讨论了邻接矩阵的实现,本篇讨论邻接表的实现

GraphLink.h

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "Graph.h"  
  2. #include <iostream>  
  3. #include <queue>  
  4. using std::cout;  
  5. using std::cin;  
  6. using std::endl;  
  7. using std::queue;  
  8.   
  9. #define N 5 // 定义图的顶点数  
  10.   
  11. template <typename T> class LList;  
  12. template <typename T> class GraphLink;  
  13. struct ListUnit//邻接表表目中数据部分的结构定义  
  14. {  
  15.     int weight; //边的权  
  16.     int vertex;//边的终点  
  17. };  
  18.   
  19. template <typename T>  
  20. class Link //链表元素  
  21. {  
  22.   
  23.     friend class GraphLink<T>;  
  24.     friend class LList<T>;  
  25.     T element;//表目的数据  
  26.     Link<T> *next; //表目指针,指向下一个表目  
  27.   
  28.     Link(const T &e,Link<T> *n = nullptr)//构造函数  
  29.     {  
  30.         element = e;  
  31.         next = n;  
  32.     }  
  33.   
  34.     Link(Link<T> *n = nullptr)//构造函数  
  35.     {  
  36.         next = n;  
  37.     }  
  38.   
  39. };  
  40.   
  41. template <typename T>  
  42. class LList  
  43. {  
  44. private:  
  45.     void removeAll() //释放边表所有表目占据的空间  
  46.     {  
  47.         Link<T> *p = head->next;  
  48.         Link<T> *temp = nullptr;  
  49.         while(p != nullptr)  
  50.         {  
  51.             temp = p;  
  52.             p = p->next;  
  53.             delete temp;  
  54.         }  
  55.     }  
  56.   
  57. public:  
  58.     Link<T> *head;//head指针并不储存任何实际元素,其存在只是为了操作方便  
  59.     LList()//构造函数  
  60.     {  
  61.         head = new Link<T>();  
  62.     }  
  63.   
  64.     ~LList()  
  65.     {  
  66.         removeAll();  
  67.     }  
  68. };  
  69.   
  70. template <typename T>  
  71. class GraphLink : public Graph  
  72. {  
  73. private:  
  74.     LList<ListUnit> *grapList; //graList是保存所有边表的数组      
  75.   
  76. public:  
  77.     GraphLink(int numVert) : Graph(numVert)  
  78.     {  
  79.          /*为graList数组申请空间,图有numVertex个顶点,则有numVertex个边表*/  
  80.         grapList = new LList<ListUnit>[numVert];  
  81.   
  82.     }  
  83.   
  84.     ~GraphLink()  
  85.     {  
  86.           
  87.         delete []grapList;  
  88.     }  
  89.   
  90.     virtual Edge firstEdge(int oneVertex)// 返回与顶点oneVertex相关联的第一条边  
  91.     {  
  92.         Edge edge;  
  93.         edge.from = oneVertex;//将顶点oneVertex作为边edge的始点  
  94.         edge.to = -1;  
  95.   
  96.          /*graList[oneVertex].head保存的是顶点oneVertex的边表, 
  97.           head->next指向顶点oneVertex的第一条边(如果head->next 
  98.                                       不为null)*/  
  99.   
  100.         Link<ListUnit> *p = grapList[oneVertex].head->next;  
  101.         if(p != nullptr)  
  102.         {  
  103.             edge.to = p->element.vertex;  
  104.             edge.weight = p->element.weight;  
  105.         }  
  106.         return edge;  
  107.     }  
  108.   
  109.     virtual Edge nextEdge(Edge preEdge)// 返回与边PreEdge有相同关联顶点的下一条边  
  110.     {  
  111.         Edge edge;  
  112.         edge.from = preEdge.from;  
  113.         edge.to = -1;  
  114.   
  115.         Link<ListUnit> *p = grapList[preEdge.from].head->next;  
  116.         while(p != nullptr && p->element.vertex <= preEdge.to)// 确定边preEdge的位置  
  117.         {  
  118.             p = p->next;  
  119.           
  120.         }  
  121.           
  122.         if(p)// 边preEdge的下一条边存在  
  123.         {  
  124.             edge.to = p->element.vertex;  
  125.             edge.weight = p->element.weight;  
  126.         }  
  127.         return edge;  
  128.     }  
  129.   
  130.     void setEdge(int from, int to, int weight)  
  131.     {  
  132.         Link<ListUnit> *p = grapList[from].head->next;  
  133.         Link<ListUnit> *pre = grapList[from].head;  
  134.         /*确定边(from,to)或<from,to>在边表中的位置,如果不存在, 
  135.                                     则边(from,to)或<from,to>为新加的一条边*/  
  136.         while(p != nullptr && p->element.vertex < to)  
  137.         {  
  138.             pre = p;//记录下前一节点  
  139.             p = p->next;  
  140.         }  
  141.   
  142.         if(p == nullptr)  
  143.         {  
  144.             Link<ListUnit> *temp = new Link<ListUnit>();  
  145.             temp->element.vertex = to;  
  146.             temp->element.weight = weight;  
  147.             pre->next = temp;  
  148.             numEdge++;  
  149.             indegree[to]++;  
  150.             return;  
  151.         }  
  152.   
  153.          /*边(from,to)或<from,to>在边表中已存在,故只需要改变边的权值*/  
  154.         if(p->element.vertex == to)  
  155.         {  
  156.             p->element.weight = weight;  
  157.             return;  
  158.         }  
  159.   
  160.         /*边(from,to)或<from,to>在边表中不存在,但在边表中其后存在其它边,则在边表中插入这条边*/  
  161.         if(p->element.vertex > to)  
  162.         {  
  163.             Link<ListUnit> *temp = new Link<ListUnit>();  
  164.             temp->element.vertex = to;  
  165.             temp->element.weight = weight;  
  166.             pre->next = temp;  
  167.             temp->next = p;  
  168.             numEdge++;  
  169.             indegree[to]++;  
  170.             return;  
  171.         }  
  172.   
  173.     }  
  174.   
  175.     void delEdge(int from, int to)  
  176.     {  
  177.         Link<ListUnit> *p = grapList[from].head->next;  
  178.         Link<ListUnit> *pre = grapList[from].head;  
  179.         /*确定边(from,to)或<from,to>在边表中的位置*/  
  180.         while(p != nullptr && p->element.vertex < to)  
  181.         {  
  182.             pre = p;//记录下前一节点  
  183.             p = p->next;  
  184.         }  
  185.   
  186.         if(p == nullptr)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作  
  187.         {  
  188.             return;  
  189.         }  
  190.   
  191.         if(p->element.vertex > to)//边(from,to)或<from,to>在边表中不存在,则不需要做任何操作  
  192.         {  
  193.             return;  
  194.         }  
  195.           
  196.         if(p->element.vertex == to)  
  197.         {  
  198.             pre->next = p->next;  
  199.             delete p;  
  200.             numEdge--;  
  201.             indegree[to]--;  
  202.             return;  
  203.         }  
  204.   
  205.     }  
  206.   
  207.     // 函数功能:初始化图  
  208.     void initGraph(GraphLink &graphM,int (*A)[N],int n)  
  209.     {  
  210.         for (int i = 0; i < n; i ++)       
  211.         {  
  212.             for (int j = 0; j < N; j ++)    
  213.             {  
  214.                 if (A[i][j] > 0)  
  215.                     graphM.setEdge(i, j, A[i][j]);  
  216.             }  
  217.         }  
  218.   
  219.     }  
  220.   
  221.     void DFS( GraphLink &graph,int vertex)  
  222.     {  
  223.         graph.mark[vertex] = VISITED;  
  224.         visit(graph,vertex);  
  225.         for(Edge edge = graph.firstEdge(vertex); graph.isEdge(edge); edge = graph.nextEdge(edge))  
  226.         {  
  227.             if(graph.mark[graph.toVertex(edge)] == UNVISITED)  
  228.             {  
  229.                 DFS(graph,graph.toVertex(edge));  
  230.             }  
  231.         }  
  232.     }  
  233.   
  234.     void BFS( GraphLink &graph,int vertex)  
  235.     {  
  236.         queue<int> q;                    // 初始化广度优先周游要用到的队列  
  237.         q.push(vertex);  
  238.         while(!q.empty())  
  239.         {  
  240.             int v = q.front();  
  241.             q.pop();  
  242.             if(graph.mark[v] == UNVISITED )  
  243.             {  
  244.                 visit(graph,v);  
  245.                 graph.mark[v] = VISITED;//标记该顶点已访问  
  246.   
  247.                 // 该顶点邻接到的每一个未访问顶点都入队  
  248.                 for(Edge edge = graph.firstEdge(v); graph.isEdge(edge); edge = graph.nextEdge(edge))  
  249.                 {  
  250.                     if(graph.mark[graph.toVertex(edge)] == UNVISITED)  
  251.                     {  
  252.                         q.push(graph.toVertex(edge));  
  253.                     }  
  254.                 }  
  255.             }  
  256.         }  
  257.     }  
  258.   
  259.     void visit(const GraphLink &graph,int vertex)          
  260.     {  
  261.         cout << "V:" << vertex << "\t";  
  262.     }  
  263. };  

测试代码

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include "GraphLink.h"  
  2. #include <iostream>  
  3.   
  4.   
  5.   
  6. int A[N][N] = {  
  7.     //        V0 V1 V2 V3 V4   
  8.     /*V0*/    0, 0, 1, 1, 0,  
  9.     /*V1*/    0, 0, 0, 1, 1,  
  10.     /*V2*/    1, 0, 0, 1, 1,  
  11.     /*V3*/    1, 1, 1, 0, 0,  
  12.     /*V4*/    0, 1, 1, 0, 0,};      //图7.2中G1表示的无向图  
  13.   
  14. int main()  
  15. {  
  16.     GraphLink<ListUnit> graphLink(N);              // 建立图   
  17.     graphLink.initGraph(graphLink, A,N); // 初始化图  
  18.     cout << "DFS: ";  
  19.     graphLink.DFS(graphLink, 0);  
  20.     cout << endl;  
  21.   
  22.     for (int i = 0; i < graphLink.verticesNum(); i++) //把Mark改回UNVISITED  
  23.         graphLink.mark[i] = UNVISITED;   
  24.   
  25.     cout << "BFS: ";  
  26.     graphLink.BFS(graphLink, 0);  
  27.     cout << endl;  
  28.   
  29.     system("pause");  
  30.     return 0;  
  31. }  

0 0
原创粉丝点击