• 数据结构之图(图的基本操作)


    由于图的基本操作的代码较多,我放到这一章来写。图可以用两种方法来存储,但是本人偏爱链表的表示方法,所以以下代码也都是是基于邻接链表的存储方式。

     1 /*
     2    以下存储结构参考严蔚敏版数据结构,不懂的可以翻阅查看  
     3 */
     4 const int UNDIGRAPH = 0;    //无向图
     5 const int DIGRAPH    = 1;    //有向图
     6 const int MAX_VERTEX_NUM = 20;
     7 
     8 typedef struct ArchNode
     9 {
    10     int    vertexIndex;        //该弧指向顶点在图中顶点数组的索引,对应vertexs[20]的下标
    11     ArchNode *nextarc;         //指向下一条弧的指针
    12     InfoTypde info;            //比如弧的权重
    13 }ArchNode;
    14 
    15 typedef struct Vertex
    16 {
    17     VertexType data;          //顶点信息
    18     ArchNode    *firstarc;    //指向第一条弧的指针
    19 }Vertex;
    20 
    21 //这样定义图有个坏处,一旦定义好,图中结点的个数就固定了!
    22 typedef struct Graph
    23 {
    24     Vertex *vertexs[MAX_VERTEX_NUM];    //存储顶点的数组,存放的是指向顶点的指针
    25     int vexNum;                         //当前图中的定点数
    26     int arcNum;                    //当前图中的弧的个数
    27     int kind;                    //图的种类,有向图还是无向图
    28 }Graph;    

    //图的创建

     1 /*
     2    初始条件:kind是图的类型,目前有有向图和无向图 两种.
     3    返回值   :无。---大部分函数都无返回值,是对图的引用进行操作的
     4 */
     5 void createGraph(Graph *&G,int kind)
     6 {
     7     if(G) G = NULL;
     8     G = (Graph *)malloc(sizeof(struct Graph));
     9     assert(NULL != G);
    10     for(int i = 0; i < MAX_VERTEX_NUM; ++i)
    11     {
    12         G->vertexs[i] = NULL;        //初始化指向顶点的指针为NULL
    13     }
    14     G->kind = kind;                    //设置图的种类
    15     G->vexNum = 0;                    //初始化图中顶点的个数
    16     G->arcNum = 0;                    //初始化图中弧的个数
    17 }

    //图的销毁

     1 /*
     2    初始条件:G存在
     3    返回值   :无。---大部分函数都无返回值,是对图的引用进行操作的
     4 */
     5 void destoryGraph(Graph *&G)
     6 {
     7     ArchNode *cur,*next;
     8     if(NULL == G)
     9         return;
    10     //遍历顶点
    11     for(int i = 0; i < G->vexNum; ++i)
    12     {
    13         if(!G->vertexs[i])
    14             continue;
    15         next = G->vertexs[i]->firstarc;
    16         cur  = G->vertexs[i]->firstarc;
    17         while(cur)
    18         {
    19             next = cur->nextarc;
    20             free(cur);
    21             cur = next;
    22         }
    23         G->vertexs[i]->firstarc = NULL;
    24     }
    25     free(G);
    26     G = NULL;
    27 }

    //向图中增加结点

     1 //向图中增加结点
     2 /*
     3     初始条件:G存在,data是结点的数据值
     4 */
     5 void addVertexToGraph(Graph *&G,VertexType data)
     6 {
     7     if(G->vexNum >= MAX_VERTEX_NUM)
     8     {
     9         cout << "Too many vertex!" << endl;
    10         return ;
    11     }
    12     for(int i = 0; i < G->vexNum; ++i)
    13     {
    14         if(!G->vertexs[i])
    15             continue;
    16         if(G->vertexs[i]->data == data)
    17         {
    18             cout << "Already exists!" << endl;
    19             return;        //不允许重复            
    20         }
    21     }
    22     Vertex *pVeterx;
    23     pVeterx = (Vertex *)malloc(sizeof(struct Vertex));
    24     pVeterx->data = data;
    25     pVeterx->firstarc = NULL;
    26     G->vertexs[G->vexNum] = pVeterx;
    27     G->vexNum++;
    28 }

    //从图中删除一个结点

     1 void delVertexFromGraph(Graph *&G,VertexType data)
     2 {
     3     bool haveThisVertex = false;
     4     ArchNode *cur,*next,*temp,*pre;
     5     Vertex *anotherVertex;
     6     if(NULL == G)
     7         return;
     8     if(G->vexNum <= 0)
     9     {
    10         cout << "Have no vertex!" << endl;
    11         return ;
    12     }
    13     for(int i = 0; i < G->vexNum; ++i)
    14     {
    15         if(!G->vertexs[i])
    16             continue;
    17         if(G->vertexs[i]->data == data)
    18         {
    19             haveThisVertex = true;
    20             //以下循环用来删除顶点所指向的弧链表
    21             next = cur = G->vertexs[i]->firstarc;
    22             if(G->kind == DIGRAPH)    //如果是有向图
    23             {
    24                 while(cur)
    25                 {
    26                     next = cur->nextarc;
    27                     free(cur);
    28                     G->arcNum --;    //弧的个数减一
    29                     cur = next;
    30                 }
    31                 G->vertexs[i] = NULL;
    32             }
    33             else if(G->kind == UNDIGRAPH)    //如果是无向图,这个麻烦点
    34             {
    35                 while(cur)
    36                 {
    37                     //找到待删除的弧的另一个结点,将它的弧链表中指向被删除结点的弧也删掉
    38                     anotherVertex = G->vertexs[cur->vertexIndex];    //找到待删除弧对应的另一个结点
    39                     temp = anotherVertex->firstarc,pre = NULL;
    40                     while(temp)                                        //这个循环是为了删除另一个结点中保存弧信息
    41                     {
    42                         if(temp->vertexIndex == i)
    43                         {
    44                             //如果是首节点
    45                             if(NULL == pre)    //或者if(NULL == pre)
    46                             {
    47                                 anotherVertex->firstarc = temp->nextarc;
    48                                 free(temp);
    49                             }
    50                             else
    51                             {
    52                                 pre->nextarc = temp->nextarc;
    53                                 free(temp);
    54                             }
    55                             break;    //找到即停止循环
    56                         }
    57                         pre = temp;
    58                         temp = temp->nextarc;
    59                     }
    60                     next = cur->nextarc;
    61                     free(cur);
    62                     G->arcNum --;    //弧的个数减一
    63                     cur = next;
    64                 }
    65                 G->vertexs[i] = NULL;
    66             }
    67             for(int j = i; j < G->vexNum - 1; ++j)
    68             {
    69                 G->vertexs[j] = G->vertexs[j + 1];
    70             }
    71             G->vertexs[j] = NULL;    //
    72             G->vexNum-- ;            //结点的个数减一
    73             break;
    74         }
    75     }
    76     if(!haveThisVertex)
    77         cout << "没有该结点!" << endl;
    78 }
    //从图中查找一个值为指定值的结点的索引
     1 //初始条件:G存在,data是指定结点的数据值
     2 int findVertexIndexInGraph(const Graph *G,VertexType data)
     3 {
     4     if(NULL == G)
     5         return -1;
     6     for(int i = 0; i < G->vexNum; ++i)
     7     {
     8         if(!G->vertexs[i])
     9             continue;
    10         if(G->vertexs[i]->data == data)
    11         {
    12             return i;
    13             break;
    14         }
    15     }
    16     return -1;
    17 }

    //向图中增加一条弧,有有向图和无向图之分

     1 //初始条件:G存在,指定起始点,和弧的权重
     2 void addArchToGraph(Graph *&G,VertexType startData,VertexType endData,InfoTypde weight = 0)
     3 {
     4     ArchNode *pArchNode,*cur;
     5     //先要找到start和end
     6     if(NULL == G)
     7         return;
     8     int startVertexIndex = findVertexIndexInGraph(G,startData);
     9     int endVertexIndex = findVertexIndexInGraph(G,endData);
    10     cur = G->vertexs[startVertexIndex]->firstarc;
    11     while(cur)
    12     {
    13         if(cur->vertexIndex == endVertexIndex)
    14         {
    15             cout << "Already have this arch!" << endl;
    16             return ;
    17         }
    18         cur = cur->nextarc;
    19     }
    20     if(startVertexIndex >= 0 && endVertexIndex >= 0)
    21     {
    22         if(G->kind == DIGRAPH)                                            //如果是有向图
    23         {
    24             pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //创建一个弧结点
    25             pArchNode->info = weight;
    26             pArchNode->nextarc = NULL;
    27             pArchNode->vertexIndex = endVertexIndex;
    28             cur = G->vertexs[startVertexIndex]->firstarc;
    29             if(NULL == cur)
    30             {
    31                 G->vertexs[startVertexIndex]->firstarc = pArchNode;
    32             }
    33             else
    34             {
    35                 while(cur->nextarc)
    36                 {
    37                     cur = cur->nextarc;
    38                 }
    39                 cur->nextarc = pArchNode;
    40             }
    41             G->arcNum ++;    //弧的条数加一
    42         }
    43         else if(G->kind == UNDIGRAPH)    //如果是无向图
    44         {
    45             pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //创建一个弧结点
    46             pArchNode->info = weight;
    47             pArchNode->nextarc = NULL;
    48             pArchNode->vertexIndex = endVertexIndex;
    49             cur = G->vertexs[startVertexIndex]->firstarc;
    50             if(NULL == cur)
    51             {
    52                 G->vertexs[startVertexIndex]->firstarc = pArchNode;
    53             }
    54             else
    55             {
    56                 while(cur->nextarc)
    57                 {
    58                     cur = cur->nextarc;
    59                 }
    60                 cur->nextarc = pArchNode;
    61             }
    62             pArchNode = (ArchNode *)malloc(sizeof(struct ArchNode));    //再创建一个弧结点
    63             pArchNode->info = weight;
    64             pArchNode->nextarc = NULL;
    65             pArchNode->vertexIndex = startVertexIndex;
    66             cur = G->vertexs[endVertexIndex]->firstarc;
    67             if(NULL == cur)
    68             {
    69                 G->vertexs[endVertexIndex]->firstarc = pArchNode;
    70             }
    71             else
    72             {
    73                 while(cur->nextarc)
    74                 {
    75                     cur = cur->nextarc;
    76                 }
    77                 cur->nextarc = pArchNode;
    78             }
    79             G->arcNum ++;    //弧的条数加一
    80         }
    81     }
    82     else
    83     {
    84         cout << "起点或终点不存在!" << endl;
    85         return ;
    86     }
    87 }

    //从图中删除一条弧

     1 //初始条件:G存在,指定要删除弧连接的两个顶点
     2 void delArchFromGraph(Graph *&G,VertexType startData,VertexType endData)
     3 {
     4     ArchNode *cur,*pre;
     5     //先要找到start和end
     6     if(NULL == G)
     7         return;
     8     int startVertexIndex = findVertexIndexInGraph(G,startData);
     9     int endVertexIndex = findVertexIndexInGraph(G,endData);
    10     if(startVertexIndex >= 0 && endVertexIndex >= 0)
    11     {
    12         if(G->kind == DIGRAPH)
    13         {
    14             cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL;
    15             while(cur)
    16             {
    17                 if(cur->vertexIndex == endVertexIndex)
    18                 {
    19                     break;
    20                 }
    21                 pre = cur;
    22                 cur = cur->nextarc;
    23             }
    24             if(NULL == cur)
    25             {
    26                 cout << "这两个结点之间没有弧!" << endl;
    27                 return ;
    28             }
    29             else
    30             {
    31                 if(NULL == pre)    //是首节点
    32                     G->vertexs[startVertexIndex]->firstarc = cur->nextarc;
    33                 else
    34                     pre->nextarc = cur->nextarc;
    35                 free(cur);
    36                 G->arcNum --;
    37             }
    38         }
    39         else if(G->kind == UNDIGRAPH)
    40         {
    41             cur = G->vertexs[startVertexIndex]->firstarc,pre = NULL;
    42             while(cur)
    43             {
    44                 if(cur->vertexIndex == endVertexIndex)
    45                 {
    46                     break;
    47                 }
    48                 pre = cur;
    49                 cur = cur->nextarc;
    50             }
    51             if(NULL == cur)
    52             {
    53                 cout << "这两个结点之间没有弧!" << endl;
    54                 return ;
    55             }
    56             else
    57             {
    58                 if(NULL == pre)    //是首节点
    59                     G->vertexs[startVertexIndex]->firstarc = cur->nextarc;
    60                 else
    61                     pre->nextarc = cur->nextarc;
    62                 free(cur);
    63                 //G->arcNum --;
    64             }
    65 
    66             cur = G->vertexs[endVertexIndex]->firstarc,pre = NULL;
    67             while(cur)
    68             {
    69                 if(cur->vertexIndex == startVertexIndex)
    70                 {
    71                     break;
    72                 }
    73                 pre = cur;
    74                 cur = cur->nextarc;
    75             }
    76             if(NULL == cur)
    77             {
    78                 cout << "这两个结点之间没有弧!" << endl;
    79                 return ;
    80             }
    81             else
    82             {
    83                 if(NULL == pre)    //是首节点
    84                     G->vertexs[endVertexIndex]->firstarc = cur->nextarc;
    85                 else
    86                     pre->nextarc = cur->nextarc;
    87                 free(cur);
    88                 G->arcNum --;
    89             }
    90         }
    91     }
    92     else
    93     {
    94         cout << "起点或终点不存在!" << endl;
    95         return ;
    96     }
    97 }

    //深度优先遍历

     1 //初始条件:图G存在
     2 void DFSdetails(const Graph *G,int i,int satusArr[])
     3 {
     4     ArchNode *cur;
     5     if(satusArr[i] == 1 )
     6         return;
     7     cout << G->vertexs[i]->data << " ";
     8     satusArr[i] = 1;
     9     cur = G->vertexs[i]->firstarc;
    10     while(cur)
    11     {
    12         DFSdetails(G,cur->vertexIndex,satusArr);
    13         cur = cur->nextarc;
    14     }
    15 }
    16 
    17 void DFS(const Graph *G)
    18 {
    19     int satusArr[MAX_VERTEX_NUM] = {0};
    20     cout << "深度优先遍历:";
    21     if(NULL == G)
    22         return;
    23     for(int i = 0; i < G->vexNum; ++i)
    24     {
    25         DFSdetails(G,i,satusArr);
    26     }
    27     cout << endl;
    28 }
  • 相关阅读:
    一个用于录制用户输入操作并实时回放的小工具
    Ubuntu 14.04 下安装wiznote客户端
    lombok @EqualsAndHashCode 注解的影响
    初始化数据库和导入数据
    com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver的区别 serverTimezone设定
    fastjson如何指定字段不序列化
    Mybatis 查询tinyint(1)的数据库字段时会自动转换成boolean类型
    Maven中settings.xml的配置项说明
    logback的使用和logback.xml详解
    解决Eureka Server不踢出已关停的节点的问题
  • 原文地址:https://www.cnblogs.com/zhuwbox/p/3649013.html
Copyright © 2020-2023  润新知